"""Basic API for Caddy"""

# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/00_core.ipynb.

# %% auto 0
__all__ = ['acme_path', 'srvs_path', 'rts_path', 'get_id', 'get_path', 'gid', 'has_id', 'gcfg', 'has_path', 'pid', 'pcfg',
           'nested_setdict', 'path2keys', 'keys2path', 'nested_setcfg', 'init_path', 'get_acme_config',
           'add_acme_config', 'init_routes', 'setup_caddy', 'add_route', 'del_id', 'add_reverse_proxy']

# %% ../nbs/00_core.ipynb 3
import os, subprocess, httpx, json
from fastcore.utils import *
from httpx import HTTPStatusError, get as xget, post as xpost, patch as xpatch, put as xput, delete as xdelete, head as xhead

# %% ../nbs/00_core.ipynb 5
def get_id(path):
    "Get a ID full URL from a path"
    if path[0 ]!='/': path = '/'+path
    if path[-1]!='/': path = path+'/'
    return f'http://localhost:2019/id{path}'

# %% ../nbs/00_core.ipynb 8
def get_path(path):
    "Get a config full URL from a path"
    if path[0 ]!='/': path = '/'+path
    if path[-1]!='/': path = path+'/'
    return f'http://localhost:2019/config{path}'

# %% ../nbs/00_core.ipynb 10
def gid(path='/'):
    "Gets the id at `path`"
    response = xget(get_id(path))
    response.raise_for_status()
    return dict2obj(response.json())

# %% ../nbs/00_core.ipynb 11
def has_id(id):
    "Check if `id` is set up"
    try: gid(id)
    except HTTPStatusError: return False
    return True

# %% ../nbs/00_core.ipynb 12
def gcfg(path='/', method='get'):
    "Gets the config at `path`"
    f = getattr(httpx, method)
    response = f(get_path(path))
    response.raise_for_status()
    return dict2obj(response.json())

# %% ../nbs/00_core.ipynb 13
def has_path(path):
    "Check if `path` is set up"
    try: gcfg(path)
    except HTTPStatusError: return False
    return True

# %% ../nbs/00_core.ipynb 15
def pid(d, path='/', method='post'):
    "Puts the config `d` into `path`"
    f = getattr(httpx, method)
    response = f(get_id(path), json=obj2dict(d))
    response.raise_for_status()
    return response.text or None

# %% ../nbs/00_core.ipynb 16
def pcfg(d, path='/', method='post'):
    "Puts the config `d` into `path`"
    f = getattr(httpx, method)
    response = f(get_path(path), json=obj2dict(d))
    response.raise_for_status()
    return response.text or None

# %% ../nbs/00_core.ipynb 18
def nested_setdict(sd, value, *keys):
    "Returns `sd` updated to set `value` at the path `keys`"
    d = sd
    for key in keys[:-1]: d = d.setdefault(key, {})
    d[keys[-1]] = value
    return sd

# %% ../nbs/00_core.ipynb 20
def path2keys(path):
    "Split `path` by '/' into a list"
    return path.strip('/').split('/')

# %% ../nbs/00_core.ipynb 22
def keys2path(*keys):
    "Join `keys` into a '/' separated path"
    return '/'+'/'.join(keys)

# %% ../nbs/00_core.ipynb 24
def nested_setcfg(value, *keys):
    d = nested_setdict(gcfg(), value, *keys)
    return pcfg(d)

# %% ../nbs/00_core.ipynb 25
def init_path(path, skip=0):
    sp = []
    for i,p in enumerate(path2keys(path)):
        sp.append(p)
        if i<skip: continue
        pcfg({}, keys2path(*sp))

# %% ../nbs/00_core.ipynb 28
acme_path = '/apps/tls/automation'
def get_acme_config(token):
    prov = { "provider": { "name": "cloudflare", "api_token": token } }
    return {
        "module": "acme",
        "challenges": { "dns": prov }
    }

# %% ../nbs/00_core.ipynb 29
def add_acme_config(cf_token):
    if has_path(acme_path): return
    init_path(acme_path)
    val = [get_acme_config(cf_token)]
    pcfg([{'issuers':val}], acme_path+'/policies')

# %% ../nbs/00_core.ipynb 33
srvs_path = '/apps/http/servers'
rts_path = srvs_path+'/srv0/routes'

# %% ../nbs/00_core.ipynb 34
def init_routes(srv_name='srv0'):
    "Create basic http server/routes config"
    if has_path(srvs_path): return
    init_path(srvs_path, skip=1)
    ir = {'listen': [':80', ':443'], 'routes': []}
    pcfg(ir, f"{srvs_path}/{srv_name}")

# %% ../nbs/00_core.ipynb 36
def setup_caddy(cf_token, srv_name='srv0'):
    "Create SSL config and HTTP app skeleton"
    add_acme_config(cf_token)
    init_routes(srv_name)

# %% ../nbs/00_core.ipynb 38
def add_route(route):
    "Add `route` dict to config"
    return pcfg(route, rts_path)

# %% ../nbs/00_core.ipynb 39
def del_id(id):
    "Delete route for `id` (e.g. a host)"
    xdelete(get_id(id))

# %% ../nbs/00_core.ipynb 41
def add_reverse_proxy(from_host, to_url):
    "Create a reverse proxy handler"
    if has_id(from_host): del_id(from_host)
    route = {
        "handle": [{
            "handler": "reverse_proxy",
            "upstreams": [{"dial": to_url}]
        }],
        "match": [{"host": [from_host]}],
        "@id": from_host,
        "terminal": True
    }
    add_route(route)
