import "#elements/ak-dual-select/ak-dual-select-provider";
import "#elements/chips/Chip";
import "#elements/chips/ChipGroup";
import "#elements/forms/HorizontalFormElement";
import "#elements/forms/SearchSelect/index";
import "#components/ak-text-input";

import { DEFAULT_CONFIG } from "#common/api/config";
import { PFSize } from "#common/enums";

import { DataProvision, DualSelectPair } from "#elements/ak-dual-select/types";
import { ModelForm } from "#elements/forms/ModelForm";

import {
    InitialPermissions,
    Permission,
    RbacApi,
    RbacRolesListRequest,
    Role,
} from "@goauthentik/api";

import { msg } from "@lit/localize";
import { html, TemplateResult } from "lit";
import { customElement } from "lit/decorators.js";
import { ifDefined } from "lit/directives/if-defined.js";

export function rbacPermissionPair(item: Permission): DualSelectPair {
    const appLabel = item.appLabelVerbose || item.appLabel || "";
    const modelLabel = item.modelVerbose || item.model || "";
    const descriptor = `${appLabel} / ${modelLabel} (${item.codename})`;
    return [
        item.id.toString(),
        html`<div class="selection-main">${item.name}</div>
            <div class="selection-desc">${descriptor}</div>`,
        `${item.name} ${descriptor}`,
    ];
}

@customElement("ak-initial-permissions-form")
export class InitialPermissionsForm extends ModelForm<InitialPermissions, string> {
    public static override verboseName = msg("Initial Permissions");
    public static override verboseNamePlural = msg("Initial Permissions");

    public override size = PFSize.XLarge;

    loadInstance(pk: string): Promise<InitialPermissions> {
        return new RbacApi(DEFAULT_CONFIG).rbacInitialPermissionsRetrieve({
            id: Number(pk),
        });
    }

    getSuccessMessage(): string {
        return this.instance
            ? msg("Successfully updated initial permissions.")
            : msg("Successfully created initial permissions.");
    }

    async send(data: InitialPermissions): Promise<InitialPermissions> {
        if (this.instance?.pk) {
            return new RbacApi(DEFAULT_CONFIG).rbacInitialPermissionsPartialUpdate({
                id: this.instance.pk,
                patchedInitialPermissionsRequest: data,
            });
        }
        return new RbacApi(DEFAULT_CONFIG).rbacInitialPermissionsCreate({
            initialPermissionsRequest: data,
        });
    }

    protected override renderForm(): TemplateResult {
        return html`<form class="pf-c-form pf-m-horizontal">
            <ak-text-input
                label=${msg("Initial Permission Name")}
                placeholder=${msg("Type a name for these initial permissions...")}
                required
                name="name"
                value="${ifDefined(this.instance?.name)}"
            >
            </ak-text-input>
            <ak-form-element-horizontal label=${msg("Role")} required name="role">
                <ak-search-select
                    placeholder=${msg("Select a role...")}
                    .fetchObjects=${async (query?: string): Promise<Role[]> => {
                        const args: RbacRolesListRequest = {
                            ordering: "name",
                        };
                        if (query !== undefined) {
                            args.search = query;
                        }
                        const roles = await new RbacApi(DEFAULT_CONFIG).rbacRolesList(args);
                        return roles.results;
                    }}
                    .renderElement=${(role: Role): string => {
                        return role.name;
                    }}
                    .renderDescription=${(role: Role): TemplateResult => {
                        return html`${role.name}`;
                    }}
                    .value=${(role: Role | undefined): string | undefined => {
                        return role?.pk;
                    }}
                    .selected=${(role: Role): boolean => {
                        return this.instance?.role === role.pk;
                    }}
                >
                </ak-search-select>
                <p class="pf-c-form__helper-text">
                    ${msg(
                        "When a user with the selected Role creates an object, the Initial Permissions will be applied to that object.",
                    )}
                </p>
            </ak-form-element-horizontal>
            <ak-form-element-horizontal label=${msg("Permissions")} name="permissions">
                <ak-dual-select-provider
                    .provider=${(page: number, search?: string): Promise<DataProvision> => {
                        return new RbacApi(DEFAULT_CONFIG)
                            .rbacPermissionsList({
                                page: page,
                                search: search,
                            })
                            .then((results) => {
                                return {
                                    pagination: results.pagination,
                                    options: results.results.map(rbacPermissionPair),
                                };
                            });
                    }}
                    .selected=${(this.instance?.permissionsObj ?? []).map(rbacPermissionPair)}
                    available-label="${msg("Available Permissions")}"
                    selected-label="${msg("Selected Permissions")}"
                ></ak-dual-select-provider>
                <p class="pf-c-form__helper-text">
                    ${msg("Permissions to grant when a new object is created.")}
                </p>
            </ak-form-element-horizontal>
        </form>`;
    }
}

declare global {
    interface HTMLElementTagNameMap {
        "ak-initial-permissions-form": InitialPermissionsForm;
    }
}
