#!/usr/bin/env python3
"""A very simple ocm implementation"""

__version__ = "0.0.1"

import argparse
import sys
import yaml
import uuid
from http.server import BaseHTTPRequestHandler, HTTPServer
from os import environ as env
from os import path, makedirs
from urllib.parse import urlparse

import pwd
import requests


class OCMHandler(BaseHTTPRequestHandler):
    def do_GET(self):
        self.send_response(200)
        self.end_headers()
        self.wfile.write(b"Hello, world!")


class OCM:
    port: int
    host: str
    server: HTTPServer
    dir: str
    legacy_mode = False
    config_dir: str
    config: dict
    config_file: str
    user: str
    fullname: str

    def __init__(self, dir: str = env["PWD"]):
        self.user = env["USER"]
        self.fullname = pwd.getpwnam(self.user).pw_gecos.strip(',')
        self.dir = dir
        self.config_dir = path.join(env["HOME"], ".config/ocm")
        self.config_file = path.join(self.config_dir, "config.yaml")
        if not path.isdir(self.config_dir):
            makedirs(self.config_dir)
        if not path.isfile(self.config_file):
            with open(self.config_file, "w") as f:
                config = {self.user: {}}
                f.write(yaml.dump(config))
        self.read_config()

    def read_config(self):
        with open(self.config_file, "r") as f:
            self.config = yaml.load(f, Loader=yaml.FullLoader)

    def write_config(self):
        with open(self.config_file, "w") as f:
            f.write(yaml.dump(self.config))

    def get_share_payload(self, provider_id: str) -> dict:
        if self.legacy_mode:
            return {
                "name": self.config[self.user][provider_id]["name"],
                "owner": self.user,
                "permission":
                    self.config[self.user][provider_id]["permission"],
                "protocol": {
                    "name": "webdav",
                    "options": {
                        "sharedSecret":
                            self.config[self.user][provider_id]["token"],
                        "permissions":
                            '{http://open-cloud-mesh.org/ns}share-permissions'
                    }
                },
                "providerId": provider_id,
                "resourceType": "file",
                    # self.config[self.user][provider_id]["resourceType"],
                "shareType": self.config[self.user][provider_id]["shareType"],
                "shareWith": self.config[self.user][provider_id]["shareWith"],
            }
        return {}

    def main(self):
        parser = argparse.ArgumentParser()
        subparsers = parser.add_subparsers(dest="command")
        receive_parser = subparsers.add_parser("receive")
        receive_parser.add_argument("--port", type=int, default=8080)
        receive_parser.add_argument("--host", type=str, default="localhost")
        receive_parser.add_argument("--directory", type=str, default=self.dir)

        share_parser = subparsers.add_parser("share")
        share_group = share_parser.add_mutually_exclusive_group(required=True)
        share_group.add_argument("--file", type=str)
        share_group.add_argument("--directory", type=str)
        share_parser.add_argument("--to", type=str, required=True)
        args = parser.parse_args()

        if args.command == "receive":
            self.port = args.port
            self.host = args.host
            self.dir = args.directory
            self.server = HTTPServer((self.host, self.port), OCMHandler)
            self.receive()
        elif args.command == "share":
            self.share(args.file, args.directory, args.to)
        else:
            parser.print_help()

    def receive(self):
        self.server.serve_forever()

    def create_share(self, receiver, resource_type, name) -> str:
        provider_id = uuid.uuid4().hex
        self.config[self.user][provider_id] = {
            "name": name,
            "permission": "read",
            "resourceType": resource_type,
            "shareType": "user",
            "shareWith": receiver,
            "token": uuid.uuid4().hex,
        }
        self.write_config()

        return provider_id

    def share(self, file, directory, to):
        uparse = urlparse(to)
        receiver = uparse.username
        if not receiver:
            print("Username not specified")
            sys.exit(1)
        else:
            print("Sharing with " + receiver)
        discovery_endpoint = uparse.scheme + "://" + \
            uparse.hostname + "/.well-known/ocm"
        req = requests.get(discovery_endpoint)
        if req.status_code != 200:
            print("Could not find ocm-provider at " + discovery_endpoint)
            print("Trying again with legacy endpoint")
            # Fallback on legacy endpoint
            discovery_endpoint = uparse.scheme + \
                '://' + uparse.hostname + "/ocm-provider"
            req = requests.get(discovery_endpoint)
            if req.status_code != 200:
                print("Could not find ocm-provider at " + discovery_endpoint)
                sys.exit(1)
        data = req.json()
        share_endpoint = data['endPoint'] + "/shares"
        enabled = data['enabled']
        if not enabled:
            print("OCM is not enabled on this server")
            sys.exit(1)
        api_version = data['apiVersion']
        resource_types = data['resourceTypes']
        if api_version == '1.0-proposal1':
            self.legacy_mode = True
        #     provider = uparse.hostname
        # else:
        #     provider = data['provider']

        file_or_folder = file
        resource_type = "file"
        if directory:
            file_or_folder = directory
            resource_type = "folder"

        type_supported = False
        for type in resource_types:
            if type['name'] == resource_type:
                type_supported = True
                break
        if not type_supported:
            print("Resource type " + resource_type + " is not supported")
            sys.exit(1)

        provider_id = self.create_share(
            receiver, resource_type, file_or_folder)
        payload = self.get_share_payload(provider_id)

        headers = {
            'Content-Type': 'application/json',
            'Accept': 'application/json'
        }
        share_req = requests.post(
            share_endpoint,
            headers=headers,
            json=payload)
        if share_req.status_code != 200:
            print("Error: " + str(share_req.status_code))
            print(share_req.text)
            sys.exit(1)
        share_data = share_req.json()

        print(share_data)


if __name__ == "__main__":
    try:
        ocm = OCM()
        ocm.main()
    except KeyboardInterrupt:
        print("Exiting...")
        sys.exit(0)