import json
import account
import requests
import os


# Plugin Data
info = {
    "name": "HNS Links",
    "description": "This is a plugin to quickly setup a HNS Links site<br>1. Connect varo instance with api key<br>2. Add domain to varo<br> 3. Add it to HNS Links<br>4. Wait a few minutes and readd it to HNS Links to ensure the generated TLSA is added<br>5. Wait for the DNS update to propogate (up to 7 hrs)",
    "version": "1.0",
    "author": "Nathan.Woodburn/"
}


# Functions
functions = {
    "login":{
        "name": "Login to Varo Instance",
        "type": "default",
        "description": "You need to connect to a varo instance to setup the dns for domains",
        "params": {
            "instance": {
                "name":"Varo Instance (eg. domains.hns.au)",
                "type":"text"
            },
            "key": {
                "name":"API Key",
                "type":"text"
            }
        },
        "returns": {
            "status": 
            {
                "name": "Status",
                "type": "text"
            }
        }
    },
    "addDomain":{
        "name": "Add domain to varo",
        "type": "default",
        "description": "Add a domain to Varo",
        "params": {
            "domain": {
                "name":"Domain",
                "type":"text"
            }
        },
        "returns": {
            "status": 
            {
                "name": "Status of the function",
                "type": "text"
            }
        }
    
    },
    "hnslinks":{
        "name": "Add domain to HNS Links with wallet address",
        "type": "default",
        "description": "Add a domain to HNS Links",
        "params": {
            "domain": {
                "name":"Domain",
                "type":"text"
            }
        },
        "returns": {
            "status": 
            {
                "name": "Status of the function",
                "type": "text"
            }
        }
    },
    "edit": {
        "name":" Edit HNS Links",
        "type": "default",
        "description": "Login and Edit your HNS Links",
        "params": {
            "domain": {
                "name":"Domain",
                "type":"text"
            }
        },
        "returns": {
            "url": 
            {
                "name": "Login URL",
                "type": "list"
            }
        }
    }
}

def login(params, authentication):
    instance = params["instance"]
    key = params["key"]
    
    # Test Connection
    if instance == "":
        return {"status":"Please enter a valid instance"}
    instance = instance.replace("https://","")
    instance = instance.replace("http://","")
    if instance[-1] == "/":
        instance = instance[:-1]

    try:
        # Authorization: Bearer <API Key>
        response = requests.post("https://" + instance + "/api", json={"action":"getInfo"}, headers={"Authorization": "Bearer " + key})
        if response.status_code != 200:
            return {"status":"Error connecting to instance"}
    except:
        return {"status":"Error connecting to instance"}
        
    with open("user_data/hnslinks.json", "w") as f:
        json.dump({"instance":instance,"key":key},f)
    return {"status":"Connected to " + instance}



def addDomain(params, authentication):
    # Add a domain to Varo
    domain = params["domain"]

    if not os.path.exists("user_data/hnslinks.json"):
        return {"status": "Missing Varo API or instance"}

    with open("user_data/hnslinks.json", "r") as f:
        auth = json.load(f)
        if not auth:
            return {"status": "Missing Varo API or instance"}
        if 'key' not in auth or 'instance' not in auth:
            return {"status": "Missing Varo API or instance"}
        api = auth["key"]
        instance = auth["instance"]
    
    headers = {"Authorization": f"Bearer {api}"}
    data = {
        "action": "getZones"
    }
    zones = requests.post(f"https://{instance}/api", json=data, headers=headers)
    if zones.status_code != 200:
        return {"status": "Error connecting to Varo"}
    if zones.json()["success"] != True:
        return {"status": "Error connecting to Varo"}
    
    zones = zones.json()["data"]
    for zone in zones:
        if zone["name"] == domain:
            return {"status": "Domain already exists"}
        
    # Check domain is owned by user
    wallet = authentication.split(":")[0]
    owned = account.getDomains(wallet)
    # Only keep owned domains ["name"]
    ownedNames = [domain["name"] for domain in owned]
    if domain not in ownedNames:
        return {"status": "Domain not owned by user"}
    
    data = {
        "action": "createZone",
        "domain": domain
    }
    response = requests.post(f"https://{instance}/api", json=data, headers=headers)
    if response.status_code != 200:
        return {"status": "Error connecting to Varo"}
    if response.json()["success"] != True:
        return {"status": "Error connecting to Varo"}
    zoneID = response.json()["data"]["zone"]
    data = {
        "action": "showZone",
        "zone": zoneID
    }
    response = requests.post(f"https://{instance}/api", json=data, headers=headers)
    if response.status_code != 200:
        return {"status": "Error connecting to Varo"}
    if response.json()["success"] != True:
        return {"status": "Error connecting to Varo"}
    zone = response.json()["data"]
    
    dns = []
    for ns in zone['NS']:
        dns.append({'type': 'NS', 'value': ns})
    ds = zone['DS']
    ds = ds.split(' ')
    dns.append({'type': 'DS', 'keyTag': int(ds[0]), 'algorithm': int(ds[1]), 'digestType': int(ds[2]), 'digest': ds[3]})
    dns = json.dumps(dns)
    response = account.setDNS(authentication,domain,dns)
    return {"status": "Success"}

def hnslinks(params, authentication):
    # Verify domain is owned by user
    domain = params["domain"]
    wallet = authentication.split(":")[0]
    owned = account.getDomains(wallet)
    # Only keep owned domains ["name"]
    ownedNames = [domain["name"] for domain in owned]
    if domain not in ownedNames:
        return {"status": "Domain not owned by user"}
    
    # Get wallet address
    address = account.getAddress(wallet)
    if address == "":
        return {"status": "Error getting wallet address"}
    
    # Sign message hns-links
    response = account.signMessage(authentication,domain,"hns-links")
    if "error" in response and response["error"]:
        return {"status": f"Error: {response['error']}"}
    
    if 'result' not in response:
        return {"status": "Error signing message"}
    signature = response["result"]

    # Send request to hns-links
    data = {
        "domain": domain,
        "signature": signature,
        "data":{
            "title": domain,
            "description": "Connected via FireWallet",
            "address": [
                {
                    "token": "hns",
                    "address": address
                }
            ]
        }
    }
    response = requests.post("https://links.hns.au/api/v1/site", json=data)
    if response.status_code != 200:
        return {"status": "Error connecting to hns-links"}
    response = response.json()
    if "error" in response and response["error"]:
        return {"status": f"Error: {response['error']}"}
    
    ip = response["IP"]
    tlsa = response["TLSA"]
    
    # Get zones from varo
    with open("user_data/hnslinks.json", "r") as f:
        auth = json.load(f)
        if not auth:
            return {"status": "Missing Varo API or instance"}
        if 'key' not in auth or 'instance' not in auth:
            return {"status": "Missing Varo API or instance"}
        api = auth["key"]
        instance = auth["instance"]
    
    response = requests.post(f"https://{instance}/api", json={"action":"getZones"}, headers={"Authorization": f"Bearer {api}"})
    if response.status_code != 200:
        return {"status": "Error connecting to Varo"}
    if response.json()["success"] != True:
        return {"status": "Error connecting to Varo"}
    zones = response.json()["data"]
    for zone in zones:
        if zone["name"] == domain:
            zoneID = zone["id"]
            break
    if zoneID == "":
        return {"status": "Error finding zone in Varo"}
    
    response = requests.post(f"https://{instance}/api", json={"action":"getRecords","zone":zoneID},
                             headers={"Authorization": f"Bearer {api}"})
    if response.status_code != 200:
        return {"status": "Error connecting to Varo"}
    if response.json()["success"] != True:
        return {"status": "Error connecting to Varo"}
    if 'data' in response.json():
        records = response.json()["data"]
    else:
        records = []
    for record in records:
        if record["type"] == "A" and record["name"] == domain:
            response = requests.post(f"https://{instance}/api", json={"action":"deleteRecord","zone":zoneID,"record":record["uuid"]},
                                     headers={"Authorization": f"Bearer {api}"})
            if response.status_code != 200:
                return {"status": "Error connecting to Varo"}
            if response.json()["success"] != True:
                return {"status": "Error connecting to Varo"}
        if record["type"] == "TLSA" and record["name"] == f"_443._tcp.{domain}":
            response = requests.post(f"https://{instance}/api", json={"action":"deleteRecord","zone":zoneID,"record":record["uuid"]},
                                     headers={"Authorization": f"Bearer {api}"})
            if response.status_code != 200:
                return {"status": "Error connecting to Varo"}
            if response.json()["success"] != True:
                return {"status": "Error connecting to Varo"}
    
    response = requests.post(f"https://{instance}/api", json={"action":"addRecord","zone":zoneID,"name":"@","type":"A","content":ip},
                             headers={"Authorization": f"Bearer {api}"})
    if response.status_code != 200:
        return {"status": "Error connecting to Varo"}
    if response.json()["success"] != True:
        return {"status": "Error connecting to Varo"}
    
    if tlsa != "":
        response = requests.post(f"https://{instance}/api", json={"action":"addRecord","zone":zoneID,"name":f"_443._tcp","type":"TLSA","content":tlsa},
                                    headers={"Authorization": f"Bearer {api}"})
        if response.status_code != 200:
            return {"status": "Error connecting to Varo"}
        if response.json()["success"] != True:
            return {"status": "Error connecting to Varo"}
    

    return {"status": "YAY!!! All done! Just wait a few minutes for HNS Links to fully initialize the site."}
    
    

def edit(params, authentication):
    # Verify domain is owned by user
    domain = params["domain"]
    wallet = authentication.split(":")[0]
    owned = account.getDomains(wallet)
    # Only keep owned domains ["name"]
    ownedNames = [domain["name"] for domain in owned]
    if domain not in ownedNames:
        return {"status": "Domain not owned by user"}
    
    # Get wallet address
    address = account.getAddress(wallet)
    if address == "":
        return {"status": "Error getting wallet address"}
    
    # Sign message hns-links
    response = account.signMessage(authentication,domain,"hns-links")
    if "error" in response and response["error"]:
        return {"status": f"Error: {response['error']}"}
    
    if 'result' not in response:
        return {"status": "Error signing message"}
    signature = response["result"]
    return {"url": [f"<a href=https://links.hns.au/auth?username={domain}&signature={signature} target='_blank'>Edit HNS Links</a>"]}