import { Auth } from '@genesislcap/foundation-comms';
import { Binding } from '@microsoft/fast-element';
import { Connect } from '@genesislcap/foundation-comms';
import { Constructable } from '@microsoft/fast-element';
import { Container } from '@microsoft/fast-foundation';
import { CredentialManager } from '@genesislcap/foundation-comms';
import { DefineFunction } from '@genesislcap/foundation-ui';
import { ElementStyles } from '@microsoft/fast-element';
import { FASTElement } from '@microsoft/fast-element';
import { FoundationAnalytics } from '@genesislcap/foundation-comms';
import { InterfaceSymbol } from '@microsoft/fast-foundation';
import { Message } from '@genesislcap/foundation-comms';
import { MessageBuilder } from '@genesislcap/foundation-comms';
import { PartialFASTElementDefinition } from '@microsoft/fast-element';
import { RouterConfiguration } from '@microsoft/fast-router';
import { Session } from '@genesislcap/foundation-comms';
import { SyntheticViewTemplate } from '@microsoft/fast-element';
import { TemplateElementDependency } from '@genesislcap/foundation-ui';
import { ViewTemplate } from '@microsoft/fast-element';

/**
 * @internal
 */
export declare const backButton: <T extends ConfigHost>(binding: Binding) => ViewTemplate<T, any>;

/**
 * @internal
 * @privateRemarks
 * Temp optimisation. How we handle images like this needs a broader review.
 */
export declare class BackgroundElement extends ConfigHostElement {
    connectedCallback(): void;
}

/**
 * @internal
 */
export declare class BaseRoute extends ConfigHostElement {
    auth: Auth;
    connect: Connect;
    session: Session;
    messageBuilder: MessageBuilder;
    credentialManager: CredentialManager;
    host: string;
    organisation: string;
    username: string;
    email: string;
    password: string;
    password2: string;
    showPasswords: boolean;
    message: string;
    hasErrors: boolean;
    isSubmitting: boolean;
    connectedCallback(): void;
    onSubmit(): Promise<void>;
    ensureConnection(): Promise<boolean>;
    setError(message: string): void;
    clearError(): void;
    get orgUsername(): string;
    onBack: () => Promise<void>;
    onNavigate: (routeName: Routes, params?: {}) => Promise<void>;
    queueOnBack(delay?: number): void;
    autofill(): Promise<boolean>;
    storeCredentials(password?: string): void;
    sendMessage<T = any>(message: Message<T>, successFeedback?: string, successCallback?: (result: any) => void): Promise<void>;
}

/**
 * @internal
 */
export declare type ConfigHost = {
    config: LoginConfig;
};

/**
 * @internal
 * @privateRemarks
 * For services / constructor injection, using @optional(LoginConfig) config = defaultLoginConfig; works as expected.
 * However, for elements, the @optional decorator isn't viable. This base element provides an alternative approach.
 */
export declare class ConfigHostElement extends FASTElement implements ConfigHost {
    container: Container;
    config: LoginConfig;
    connectedCallback(): void;
}

/**
 * @internal
 * @privateRemarks
 * Potential optimisation ahead of workflow / statemachine based smart forms integration, but needs tagFor.
 * Feels a bit at odds with the declarative nature we're aiming for, but will await review.
 */
export declare const configurableTextField: <T extends ConfigHost>(name: keyof FieldConfigMap | [name: keyof FieldConfigMap, valueKey: string], type: string, autofocus?: boolean, autocomplete?: string, className?: string, labelOverride?: string, testIdOverride?: string, required?: boolean) => ViewTemplate<T, any>;

/**
 * Configure the login micro frontend settings.
 *
 * @remarks
 * This is primarily for general settings, rather than re-defining the element, static templating / style changes.
 *
 * @param container - DI container.
 * @param config - A partial LoginConfig.
 *
 * @example Configuring login on lazy load
 * ```ts
 * name: 'login',
 * path: 'login',
 * title: 'Login',
 * element: async () => {
 *   const { configure, define, defaultLoginConfig } = await import('@genesislcap/foundation-login');
 *   configure(this.container, {
 *     autoConnect: true,
 *     omitRoutes: ['request-account'],
 *     fields: {
 *       ...defaultLoginConfig.fields,
 *       organisation: {
 *         label: 'CompID',
 *       },
 *     },
 *     defaultRedirectUrl: 'dashboard',
 *     logo: loginLogo,
 *     background: loginBG,
 *   });
 *   // You can import and return `Login` directly here or re-define it completely via `define`.
 *   return define({
 *     name: `nexus-login`,
 *   });
 * },
 * layout: loginLayout,
 * settings: { public: true },
 * childRouters: true,
 * ```
 *
 * @public
 * @privateRemarks
 * We can tailor the spreading logic after we put it to use. Keeping it simple for now.
 */
export declare function configure(container: Container, config: Partial<LoginConfig>): void;

/**
 * @public
 */
export declare const defaultApiHost: string;

/**
 * Default LoginConfig DI implementation.
 * @public
 */
export declare const defaultLoginConfig: LoginConfig;

/**
 * @internal
 */
export declare const defaultOnBackMS = 3000;

/**
 * @public
 */
export declare const defaultOrganisation: string;

/**
 * @public
 */
export declare const defaultPassword: string;

/**
 * @public
 */
export declare const defaultSocketExt: string;

/**
 * The default template options this MF has been created with.
 * @beta
 * @privateRemarks
 * This will likely evolve into the shell style PWA + FDC3 manifest setup, but that needs more work to evolve into MVP.
 * Hosts should be able to figure out everything they will need to do to fully customise a MF. Currently, they
 * import these `defaultTemplateOptions` and the host dev overrides. Each TemplateComponents key must be a mandatory
 * override, given in hosted mode the MFs won't be registering fallbacks as this would be wasteful, bloat etc.
 * I've added the components list to the package.json > config block for now, but I'm not using it here.
 */
export declare const defaultTemplateOptions: TemplateOptions;

/**
 * @public
 */
export declare const defaultUser: string;

/**
 * Re-define the login micro frontend.
 *
 * @example
 * ```ts
 * import { define, styles, template, defaultTemplateOptions } from '@genesislcap/foundation-login';
 * const customTemplateOptions = {
 *   ...defaultTemplateOptions,
 *   ...customOptions,
 * }
 * export const AppLogin = define({
 *   name: `nexus-login`,
 *   template: template(customTemplateOptions),
 *   styles: css`
 *     ${styles(customTemplateOptions)}
 *     some-element {
 *       background-color: #ff00b4;
 *     }
 *  `,
 * });
 * ```
 *
 * @beta
 * @privateRemarks
 * TODO: Use LoginHosted instead of Login when elements manifest stuff lands, which will drive tagFor etc.
 */
export declare const define: DefineFunction<typeof Login>;

/**
 * @beta
 * @remarks
 * This is the main definition of this micro frontend which is exposed for user reconfiguration.
 */
export declare const definition: PartialFASTElementDefinition;

/**
 * @internal
 */
export declare const emailField: <T extends BaseRoute>() => ViewTemplate<T, any>;

/**
 * @public
 * Could be expanded to allow field ViewTemplates.
 */
export declare type FieldConfig = {
    label: string;
    /**
     * @privateRemarks
     * Added for now to apply defaults, but I'm not convinced we should do this. Could be made reactive after upgrade.
     */
    value?: any;
};

/**
 * @public
 * @privateRemarks
 * Using null to exclude the organisation field rather than boolean, as it affords cleaner value lookups in the templates.
 */
export declare type FieldConfigMap = {
    organisation: FieldConfig | null;
    username: FieldConfig;
    email: FieldConfig;
    password: FieldConfig;
};

/**
 * @public
 */
export declare const hostEnv: string;

/**
 * @public
 */
export declare const hostUrl: string;

/**
 * @public
 */
export declare interface IDP {
    id: string;
    type: string;
}

/**
 * @public
 */
export declare interface IDPResponse {
    ID: string;
    TYPE: string;
}

/**
 * A utility to check if a pathname is a route of this micro frontend.
 *
 * @param pathname - A pathname string to check, typically location.pathname, which is used when a value is omitted.
 *
 * @public
 * @privateRemarks
 * I've just put this util in for now given there's some app level direction code in place which needs review.
 */
export declare function isMFRoute(pathname?: string): boolean;

/**
 * Defines the login class which handles account authentication from the front-end
 *
 * @remarks
 *
 * Add the Login class as a router element, and it will handle the account authentication for you.
 * Requires use of `@genesislcap/foundation-comms` for the {@link @genesislcap/foundation-comms#Auth | Auth} and
 * {@link @genesislcap/foundation#Session | Session} classes.
 *
 * There are a lot of configuration options available, and different authentication types (such as login via SSO). Use
 * the modules exported `configure` and `define` functions for more power.
 *
 * @example
 * The following is an example of using it in your app, setting it up in the router configuration. This isn't a complete
 * routes confutation, but it contains all required configuration in regard to adding Login functionality.
 * ```ts
 * // Import required dependencies from the foundation-login package
 * import { Login } from '@genesislcap/foundation-login';
 * // Import required dependencies from the foundation-comms package
 * // You could also import analytics events and set them up in the NavigationContributor
 * import { Auth, Session } from '@genesislcap/foundation-comms';
 *
 * type RouterSettings = {
 *   public?: boolean;
 *   autoAuth?: boolean;
 * }
 *
 * // Define your router config
 * export class MainRouterConfig extends RouterConfiguration<RouterSettings> {
 *   // Ensure you inject in required dependencies
 *   constructor(
 *     @Auth private auth: Auth,
 *     @Session private session: Session
 *   ) {
 *     super();
 *   }
 *
 *   // Add Login as a route
 *   public configure() {
 *     ...
 *     this.routes.map(
 *       { path: '', redirect: 'login' },
 *       {
 *         path: 'login',
 *         element: Login,
 *         title: 'Login',
 *         name: 'login',
 *         layout: loginLayout,
 *         settings: { public: true },
 *         childRouters: true,
 *       },
 *       ... // Other routes config here
 *     );
 *
 *     const session = this.session;
 *     const auth = this.auth;
 *
 *     // Example of a FallbackRouteDefinition
 *     this.routes.fallback(() =>
 *       auth.isLoggedIn ? { redirect: 'not-found' } : { redirect: 'login' }
 *     );
 *
 *      // Example of a NavigationContributor
 *     this.contributors.push({
 *       navigate: async (phase) => {
 *         const settings = phase.route.settings;
 *
 *         // Could add in processes such as analytics here
 *
 *         // If public route don't block
 *         if (settings && settings.public) {
 *           return;
 *         }
 *
 *         // If logged in don't block
 *         if (auth.isLoggedIn) {
 *           return;
 *         }
 *
 *         // If autoAuth and session is valid try to connect+auto-login
 *         if (settings && settings.autoAuth && (await auth.reAuthFromSession())) {
 *           return;
 *         }
 *
 *         // Otherwise route them to login
 *         phase.cancel(() => {
 *           session.captureReturnUrl();
 *           Route.name.replace(phase.router, 'login');
 *         });
 *       },
 *     });
 *   }
 *
 *   ... // Other configuration/methods
 *
 * }
 * ```
 *
 * @public
 */
export declare class Login extends FASTElement {
    /**
     * Configuration for the routes and their associated settings.
     * The client would override this in their app with their own settings to set
     * their routes up as desired
     * @internal
     */
    config: MainRouterConfig;
    /**
     * The DI container used to register required components in {@link Login.registerDIDependencies}
     * @internal
     */
    container: Container;
    /**
     * Session controller used to manage the user's session
     * @internal
     */
    session: Session;
    /**
     * Marked true when remote components are loaded, currently unused.
     * @internal
     */
    ready: boolean;
    /**
     * DS provider / root level template.
     * @internal
     */
    provider: FASTElement;
    /**
     * @internal
     */
    connectedCallback(): Promise<void>;
    /**
     * Used to forward the user onto a logged-in session during an SSO journey
     *
     * @remarks
     *
     * Called when loading the login page via the connectedCallback() method.
     * During normal flows there will be no SSO tokens set and hence this function
     * will quit execution.
     * During an SSO journey the SSO provider will set the SSO token as a URLSearchParams
     * parameter and redirect back to us. In this case we will take this and forward the
     * user on, with their logged in session.
     *
     * There are two paths the user can take here - if they are in a popup
     * (window.opener exists) then we need to set the session and get the parent window
     * (the one which the user wants their session on) to refresh, and close the popup.
     *
     * Or if they are not in a popup then we simply set the ssoToken in the session.
     * When this component is loaded with the ssoToken then it will redirect the
     * user to their app (the `defaultRedirectUrl`).
     *
     * @internal
     */
    checkForSSOToken(): void;
    /**
     * Called from the connectedCallback
     * @internal
     */
    registerCommonComponents(): Promise<void>;
    /**
     * @internal
     */
    protected registerDIDependencies(): void;
}

/**
 * LoginConfig DI interface.
 *
 * @public
 */
export declare interface LoginConfig {
    /**
     * Connect automatically or require user to click a connect button.
     */
    autoConnect: boolean;
    /**
     * Login automatically or require user to click a login button after a connection is established.
     *
     * @remarks
     * Needs to manually be enabled in the NavigationContributor (see [2] in the example in the {@link Login} class).
     */
    autoAuth: boolean;
    /**
     * Logo styles.
     *
     * @remarks
     * Providing `null` will hide the logo. Use content: url(...); to set source.
     *
     * @example Setting a custom logo
     * ```ts
     * logo: css`
     *     content: url(${customLogoImport});
     * `,
     * ```
     */
    logo: ElementStyles | null;
    /**
     * Background styles.
     *
     * @remarks
     * See {@link https://developer.mozilla.org/en-US/docs/Web/CSS/background} for more information.
     *
     * @example Setting a custom background image
     * ```ts
     * background: css`
     *     :host {
     *         background-image: url(${customBGImport});
     *     }
     * `,
     * ```
     */
    background: ElementStyles;
    /**
     * Omit any of the internal routes except 'login' and 'not-found'.
     *
     * @remarks
     * Routes specified here will not be configured nor will any internal cross-links to them be displayed.
     *
     * @example
     * ```ts
     * omitRoutes: ['request-account'],
     * ```
     */
    omitRoutes: Exclude<Routes, 'login' | 'not-found'>[];
    /**
     * Map of configuration for each of the primary form fields.
     *
     * @remarks
     * Use to drive inclusion / exclusion, tailor labels etc.
     */
    fields: FieldConfigMap;
    /**
     * Show or hide the connection status indicator.
     */
    showConnectionIndicator: boolean;
    /**
     * The default URL to route the user to after a successful login.
     *
     * @remarks
     * Session.returnUrl set via Session.captureReturnUrl() trumps this value.
     */
    defaultRedirectUrl: string;
    /**
     * Omit certain return urls which the session service may have captured.
     *
     * @example
     * ```ts
     * omitRedirectUrls: ['/not-found'],
     * ```
     */
    omitRedirectUrls: string[];
    /**
     * SSO configuration.
     *
     * @remarks
     * Providing `null` excludes the SSO journey option completely.
     */
    sso: SSOConfig | null;
    /**
     * Display arbitrary version information.
     *
     * @remarks
     * Applications may choose to set this to display their Application release version on the login form.
     *
     * @example
     * ```ts
     * versionInformation: 'Version 3.0.0',
     * ```
     */
    versionInformation?: string;
}

/**
 * LoginConfig DI key.
 *
 * @internal
 * @privateRemarks
 * Marked as internal to stop api-extractor becoming confused cross-linking tokens with the same name.
 */
export declare const LoginConfig: InterfaceSymbol<LoginConfig>;

/**
 * @beta
 * @privateRemarks
 * A hosted version of the MF that doesn't set up a design system or components. This is what apps would use to truly
 * customise the MF for their needs via define.ts.
 */
export declare class LoginHosted extends Login {
    registerCommonComponents(): Promise<void>;
}

/**
 * @internal
 */
export declare class LogoElement extends ConfigHostElement {
}

/**
 * Base implementation of a routing used with the Login class
 *
 * @remarks
 *
 * Could be used when using the Login class as a standalone authentication method
 * with your app
 *
 * @internal
 */
export declare class MainRouterConfig extends RouterConfiguration<Settings> {
    private auth;
    private container;
    private analytics;
    private session;
    private loginConfig;
    constructor(auth: Auth, container: Container, analytics: FoundationAnalytics, session: Session, loginConfig?: LoginConfig);
    configure(): void;
    construct<T>(Type: Constructable<T>): T;
}

/**
 * @internal
 * @privateRemarks
 * Temp optimisation. How we handle images like this needs a broader review.
 */
export declare class MessageElement extends FASTElement {
    classNames: string;
    message: string;
    nonError: boolean;
    nonErrorChanged(): void;
}

/**
 * @internal
 */
export declare const organisationField: <T extends BaseRoute>() => ViewTemplate<T, any>;

/**
 * @internal
 */
export declare const password2Field: <T extends BaseRoute>(type: 'new' | 'confirmation') => ViewTemplate<T, any>;

/**
 * @internal
 */
export declare const passwordField: <T extends BaseRoute>(label?: string) => ViewTemplate<T, any>;

/**
 * @public
 */
export declare const Routes: {
    readonly login: "login";
    readonly 'request-account': "request-account";
    readonly 'reset-password': "reset-password";
    readonly 'forgot-password': "forgot-password";
    readonly verify: "verify";
    readonly protected: "protected";
    readonly 'not-found': "not-found";
};

/**
 * @public
 */
export declare type Routes = (typeof Routes)[keyof typeof Routes];

/**
 * Defines the parameters you may set on the routes.
 *
 * @remarks
 * See the example in the {@link Login} class in the router's `configure` method for usage. All parameters are Optional.
 *
 * @public
 */
export declare type Settings = {
    /**
     * Controls whether the user has to be logged in to view.
     */
    public?: boolean;
};

/**
 * @internal
 */
export declare const showPasswordsCheckbox: <T extends BaseRoute>() => ViewTemplate<T, any>;

/**
 * @public
 */
export declare type SSOConfig = {
    /**
     * Optionally toggle the SSO journey on/off by default.
     */
    toggled?: boolean;
    /**
     * The identity providers path under the current host.
     *
     * @example
     * ```ts
     * identityProvidersPath: 'sso/list'
     * ```
     */
    identityProvidersPath: string;
};

/**
 * @internal
 * @privateRemarks
 * This is used during development of this micro frontend.
 */
export declare const standaloneDefinition: PartialFASTElementDefinition;

/**
 * @public
 * @privateRemarks
 * Options cam be used to target unknown component tags in the css, such as:
 * const buttonTag = tagFor(options.button);
 * ...
 * ${buttonTag} {
 *   width: 200px;
 * }
 */
export declare const styles: (options: TemplateOptions) => ElementStyles;

/**
 * @internal
 */
export declare const submitButton: <T extends ConfigHost>(label: string, dataTestId?: string, disabled?: boolean) => ViewTemplate<T, any>;

/**
 * @internal
 */
export declare class SubmittingIndicator extends FASTElement {
    isSubmitting: boolean;
}

/**
 * @public
 */
export declare const template: (options: TemplateOptions) => ViewTemplate<Login, any>;

/**
 * @beta
 * @privateRemarks
 * The CLI can be used to monitor what is in use and needs a mapping.
 */
export declare type TemplateComponents = {
    anchor: TemplateElementDependency;
    button: TemplateElementDependency;
    card: TemplateElementDependency;
    checkbox: TemplateElementDependency;
    listboxOption: TemplateElementDependency;
    provider: TemplateElementDependency;
    router: TemplateElementDependency;
    select: TemplateElementDependency;
    textField: TemplateElementDependency;
};

/**
 * @beta
 */
export declare type TemplateOptions = TemplateComponents & {
    somePartial?: string | SyntheticViewTemplate;
};

/**
 * @internal
 */
export declare const usernameField: <T extends BaseRoute>() => ViewTemplate<T, any>;

export { }
