# (c) cavaliba.com - tests / helper

import yaml

from app_data import crypto
from app_data.data import Instance
from app_data.group import Group
from app_data.loader import load_broker
from app_data.role import Role
from app_data.user import User
from app_user.models import SirenePermission

# ---------------------------------------------------------------------------
# IAM
# ---------------------------------------------------------------------------


def add_admin_user(login="adminuser"):
    user = User(keyname=login)
    user.displayname = login
    user.create()
    datalist = [
        {"classname": "role", "_action": "update", "keyname": "role_admin", "users": [login]}
    ]
    load_broker(datalist=datalist, aaa={"perms": ["p_role_update"]})
    return user


def add_user_with_perm(login="unittest", perms=[]):
    user = User(keyname=login)
    user.displayname = login
    user.create()
    for perm_name in perms:
        SirenePermission.objects.get_or_create(keyname=perm_name)
    role_keyname = f"role_{login}"
    datalist = [
        {
            "classname": "role",
            "_action": "create",
            "keyname": role_keyname,
            "displayname": role_keyname,
            "users": [login],
            "permissions": perms,
        }
    ]
    load_broker(datalist=datalist, aaa={"perms": ["p_role_create"]})


def add_user(login="testuser01", displayname=None, is_enabled=True):
    user = User(keyname=login)
    user.displayname = displayname or login
    user.is_enabled = is_enabled
    user.create()
    return user


def add_group(name="testgroup01", displayname=None):
    g = Group(keyname=name)
    g.displayname = displayname or name
    g.create()
    return g


def add_role(name="testrole01", displayname=None):
    r = Role(keyname=name)
    r.displayname = displayname or name
    r.create()
    return r


# ---------------------------------------------------------------------------
# site, app
# ---------------------------------------------------------------------------


def add_test_sites(count=5):
    yaml_entries = []
    for i in range(1, count + 1):
        yaml_entries.append(f"""- classname: site
  keyname: site{i:02d}
  displayname: Site {i:02d}""")
    yaml_str = "\n".join(yaml_entries)
    datalist = yaml.safe_load(yaml_str)
    aaa = {"perms": ["p_data_create", "p_data_site_admin"]}
    _ = load_broker(datalist=datalist, aaa=aaa)


def add_test_apps(count=5):
    yaml_entries = []
    for i in range(1, count + 1):
        yaml_entries.append(f"""- classname: app
  keyname: app{i:02d}
  displayname: App {i:02d}""")
    yaml_str = "\n".join(yaml_entries)
    datalist = yaml.safe_load(yaml_str)
    aaa = {"perms": ["p_data_create", "p_data_app_admin"]}
    _ = load_broker(datalist=datalist, aaa=aaa)


# ---------------------------------------------------------------------------
# schema
# ---------------------------------------------------------------------------


def add_schema(
    classname="unittest",
    action="create",
    displayname=None,
    options=None,
    field_definition=None,
    verbose=False,
):
    if displayname is None:
        displayname = classname

    yaml_entry = {
        "classname": "_schema",
        "_action": action,
        "keyname": classname,
        "displayname": displayname,
    }

    if options:
        yaml_entry["_options"] = options

    if field_definition:
        yaml_entry.update(field_definition)

    datalist = [yaml_entry]
    aaa = {
        "perms": [
            "p_schema_write",
        ]
    }
    load_broker(datalist=datalist, aaa=aaa)

    from app_data.schema import Schema

    return Schema.from_name(classname)


def add_instance(classname=None, keyname=None, action="create", fields=None, verbose=False):
    yaml_entry = {"classname": classname, "_action": action, "keyname": keyname}

    if fields:
        yaml_entry.update(fields)

    datalist = [yaml_entry]

    aaa = {
        "perms": [
            "p_data_admin",
        ]
    }

    load_broker(datalist=datalist, aaa=aaa)


def add_schema_field(classname="test", fields={}, verbose=False):
    yaml_entry = {"classname": "_schema", "keyname": classname}

    # Add the field definitions directly to the schema entry
    # field_definition should be a dict like: {'field1': {...}, 'field2': {...}}
    yaml_entry.update(fields)

    datalist = [yaml_entry]

    aaa = {
        "perms": [
            "p_schema_write",
        ]
    }
    load_broker(datalist=datalist, aaa=aaa)


# ---------------------------------------------------------------------------
# pipeline
# ---------------------------------------------------------------------------


def run_pipeline(pipeline_name, schema_names, aaa=None, dryrun=False):
    from app_data.models import DataTask
    from app_data.tasks import submit_pipeline

    if aaa is None:
        aaa = {"perms": ["p_data_admin", "p_pipeline_run"]}

    handle, err = submit_pipeline(
        pipeline_name=pipeline_name,
        schema_names=schema_names,
        dryrun=dryrun,
        aaa=aaa,
        owner_type="test",
        owner_id="system",
        sync=True,
    )
    if not handle:
        return 0, 0, [err or "submit_pipeline failed"]

    dt = DataTask.objects.get(handle=handle)
    output = dt.output or {}

    total_ok = output.get("total_ok", 0)
    total_discarded = output.get("total_discarded", 0)
    errors = []
    for entry in output.get("results", []):
        errors.extend(entry.get("errors", []))

    return total_ok, total_discarded, errors


def add_pipeline_noop():

    datalist = yaml.safe_load("""
        - classname: _pipeline
          keyname: pipeline_noop
          displayname: pipeline_noop
          description: pipeline_noop
          is_enabled: True
          content: |
                csv_delimiter: '|'
                classname: test1
                keyfield: keyname
                tasks:
                - field_noop
        """)
    aaa = {"perms": ["p_pipeline_create"]}
    load_broker(datalist=datalist, aaa=aaa)


# ---------------------------------------------------------------------------
# api_key
# ---------------------------------------------------------------------------


def add_apikey_admin():

    secret = crypto.hash_create("mysecret")

    instance = Instance(classname="_apikey", keyname="test")
    data = {
        "secret": secret,
        "ip_filter": "*",
        "is_readonly": False,
        "is_enabled": True,
        "acl": "\n".join(
            [
                "p_data_admin",
                "p_info",
                "p_schema_read",
                "p_schema_write",
                "p_group_read",
                "p_role_read",
                "p_user_read",
                "p_data_access",
                "p_data_create",
                "p_data_import",
                "p_permission_read",
                "p_pipeline_run",
                "p_task_manage",
            ]
        ),
    }
    instance.merge_import(data)
    instance.create()

    return {"X-Cavaliba-Key": "test mysecret"}


def add_apikey(keyname="testkey", acl=""):

    secret = crypto.hash_create("testpassword")

    instance = Instance(classname="_apikey", keyname=keyname)
    data = {
        "secret": secret,
        "ip_filter": "*",
        "is_readonly": False,
        "is_enabled": True,
        "acl": acl,
    }
    instance.merge_import(data)
    instance.create()

    return {"X-Cavaliba-Key": f"{keyname} testpassword"}
