import $ from "jquery";
import render_compose_all_everyone from "../templates/compose_all_everyone.hbs";
import render_compose_announce from "../templates/compose_announce.hbs";
import render_compose_invite_users from "../templates/compose_invite_users.hbs";
import render_compose_not_subscribed from "../templates/compose_not_subscribed.hbs";
import render_compose_private_stream_alert from "../templates/compose_private_stream_alert.hbs";
import * as channel from "./channel";
import * as compose_error from "./compose_error";
import * as compose_pm_pill from "./compose_pm_pill";
import * as compose_state from "./compose_state";
import {$t_html} from "./i18n";
import {page_params} from "./page_params";
import * as peer_data from "./peer_data";
import * as people from "./people";
import * as settings_config from "./settings_config";
import * as settings_data from "./settings_data";
import * as stream_data from "./stream_data";
import {user_settings} from "./user_settings";
import * as util from "./util";
let user_acknowledged_all_everyone = false;
let user_acknowledged_announce = false;
let wildcard_mention;
export const announce_warn_threshold = 60;
export let wildcard_mention_large_stream_threshold = 15;
export function needs_subscribe_warning(user_id, stream_id) {
    // This returns true if all of these conditions are met:
    //  * the user is valid
    //  * the user is not already subscribed to the stream
    //  * the user has no back-door way to see stream messages
    //    (i.e. bots on public/private streams)
    //
    //  You can think of this as roughly answering "is there an
    //  actionable way to subscribe the user and do they actually
    //  need it?".
    //
    //  We expect the caller to already have verified that we're
    //  sending to a valid stream and trying to mention the user.
    const user = people.get_by_user_id(user_id);
    if (!user) {
        return false;
    }
    if (user.is_bot) {
        // Bots may receive messages on public/private streams even if they are
        // not subscribed.
        return false;
    }
    if (stream_data.is_user_subscribed(stream_id, user_id)) {
        // If our user is already subscribed
        return false;
    }
    return true;
}
export function warn_if_private_stream_is_linked(linked_stream) {
    // For PMs, we currently don't warn about links to private
    // streams, since you are specifically sharing the existence of
    // the private stream with someone.  One could imagine changing
    // this policy if user feedback suggested it was useful.
    if (compose_state.get_message_type() !== "stream") {
        return;
    }
    const compose_stream = stream_data.get_sub(compose_state.stream_name());
    if (compose_stream === undefined) {
        // We have an invalid stream name, don't warn about this here as
        // we show an error to the user when they try to send the message.
        return;
    }
    // If the stream we're linking to is not invite-only, then it's
    // public, and there is no need to warn about it, since all
    // members can already see all the public streams.
    //
    // Theoretically, we could still do a warning if there are any
    // guest users subscribed to the stream we're posting to; we may
    // change this policy if user feedback suggests it'd be an
    // improvement.
    if (!linked_stream.invite_only) {
        return;
    }
    // Don't warn if subscribers list of current compose_stream is
    // a subset of linked_stream's subscribers list, because
    // everyone will be subscribed to the linked stream and so
    // knows it exists.  (But always warn Zephyr users, since
    // we may not know their stream's subscribers.)
    if (
        peer_data.is_subscriber_subset(compose_stream.stream_id, linked_stream.stream_id) &&
        !page_params.realm_is_zephyr_mirror_realm
    ) {
        return;
    }
    const stream_name = linked_stream.name;
    const warning_area = $("#compose_private_stream_alert");
    const context = {stream_name};
    const new_row = render_compose_private_stream_alert(context);
    warning_area.append(new_row);
    warning_area.show();
}
export function warn_if_mentioning_unsubscribed_user(mentioned) {
    if (compose_state.get_message_type() !== "stream") {
        return;
    }
    // Disable for Zephyr mirroring realms, since we never have subscriber lists there
    if (page_params.realm_is_zephyr_mirror_realm) {
        return;
    }
    const user_id = mentioned.user_id;
    if (mentioned.is_broadcast) {
        return; // don't check if @all/@everyone/@stream
    }
    const stream_name = compose_state.stream_name();
    if (!stream_name) {
        return;
    }
    const sub = stream_data.get_sub(stream_name);
    if (!sub) {
        return;
    }
    if (needs_subscribe_warning(user_id, sub.stream_id)) {
        const error_area = $("#compose_invite_users");
        const existing_invites_area = $("#compose_invite_users .compose_invite_user");
        const existing_invites = Array.from($(existing_invites_area), (user_row) =>
            Number.parseInt($(user_row).data("user-id"), 10),
        );
        if (!existing_invites.includes(user_id)) {
            const context = {
                user_id,
                stream_id: sub.stream_id,
                name: mentioned.full_name,
                can_subscribe_other_users: settings_data.user_can_subscribe_other_users(),
            };
            const new_row = render_compose_invite_users(context);
            error_area.append(new_row);
        }
        error_area.show();
    }
}
function show_all_everyone_warnings(stream_id) {
    const stream_count = peer_data.get_subscriber_count(stream_id) || 0;
    const all_everyone_template = render_compose_all_everyone({
        count: stream_count,
        mention: wildcard_mention,
    });
    const error_area_all_everyone = $("#compose-all-everyone");
    // only show one error for any number of @all or @everyone mentions
    if (!error_area_all_everyone.is(":visible")) {
        error_area_all_everyone.append(all_everyone_template);
    }
    error_area_all_everyone.show();
    user_acknowledged_all_everyone = false;
}
export function clear_all_everyone_warnings() {
    $("#compose-all-everyone").hide();
    $("#compose-all-everyone").empty();
    $("#compose-send-status").hide();
}
function show_announce_warnings(stream_id) {
    const stream_count = peer_data.get_subscriber_count(stream_id) || 0;
    const announce_template = render_compose_announce({count: stream_count});
    const error_area_announce = $("#compose-announce");
    if (!error_area_announce.is(":visible")) {
        error_area_announce.append(announce_template);
    }
    error_area_announce.show();
    user_acknowledged_announce = false;
}
export function clear_announce_warnings() {
    $("#compose-announce").hide();
    $("#compose-announce").empty();
    $("#compose-send-status").hide();
}
export function set_user_acknowledged_all_everyone_flag(value) {
    user_acknowledged_all_everyone = value;
}
export function set_user_acknowledged_announce_flag(value) {
    user_acknowledged_announce = value;
}
export function get_invalid_recipient_emails() {
    const private_recipients = util.extract_pm_recipients(
        compose_state.private_message_recipient(),
    );
    const invalid_recipients = private_recipients.filter(
        (email) => !people.is_valid_email_for_compose(email),
    );
    return invalid_recipients;
}
function check_unsubscribed_stream_for_send(stream_name, autosubscribe) {
    let result;
    if (!autosubscribe) {
        return "not-subscribed";
    }
    // In the rare circumstance of the autosubscribe option, we
    // *Synchronously* try to subscribe to the stream before sending
    // the message.  This is deprecated and we hope to remove it; see
    // #4650.
    channel.post({
        url: "/json/subscriptions/exists",
        data: {stream: stream_name, autosubscribe: true},
        async: false,
        success(data) {
            if (data.subscribed) {
                result = "subscribed";
            } else {
                result = "not-subscribed";
            }
        },
        error(xhr) {
            if (xhr.status === 404) {
                result = "does-not-exist";
            } else {
                result = "error";
            }
        },
    });
    return result;
}
export function wildcard_mention_allowed() {
    if (
        page_params.realm_wildcard_mention_policy ===
        settings_config.wildcard_mention_policy_values.by_everyone.code
    ) {
        return true;
    }
    if (
        page_params.realm_wildcard_mention_policy ===
        settings_config.wildcard_mention_policy_values.nobody.code
    ) {
        return false;
    }
    if (
        page_params.realm_wildcard_mention_policy ===
        settings_config.wildcard_mention_policy_values.by_stream_admins_only.code
    ) {
        // TODO: Check the user's stream-level role once stream-level admins exist.
        return page_params.is_admin;
    }
    if (
        page_params.realm_wildcard_mention_policy ===
        settings_config.wildcard_mention_policy_values.by_moderators_only.code
    ) {
        return page_params.is_admin || page_params.is_moderator;
    }
    // TODO: Uncomment when we add support for stream-level administrators.
    // if (
    //     page_params.realm_wildcard_mention_policy ===
    //     settings_config.wildcard_mention_policy_values.by_admins_only.code
    // ) {
    //     return page_params.is_admin;
    // }
    if (
        page_params.realm_wildcard_mention_policy ===
        settings_config.wildcard_mention_policy_values.by_full_members.code
    ) {
        if (page_params.is_admin) {
            return true;
        }
        const person = people.get_by_user_id(page_params.user_id);
        const current_datetime = new Date(Date.now());
        const person_date_joined = new Date(person.date_joined);
        const days = (current_datetime - person_date_joined) / 1000 / 86400;
        return days >= page_params.realm_waiting_period_threshold && !page_params.is_guest;
    }
    return !page_params.is_guest;
}
export function set_wildcard_mention_large_stream_threshold(value) {
    wildcard_mention_large_stream_threshold = value;
}
function validate_stream_message_mentions(stream_id) {
    const stream_count = peer_data.get_subscriber_count(stream_id) || 0;
    // If the user is attempting to do a wildcard mention in a large
    // stream, check if they permission to do so.
    if (wildcard_mention !== null && stream_count > wildcard_mention_large_stream_threshold) {
        if (!wildcard_mention_allowed()) {
            compose_error.show(
                $t_html({
                    defaultMessage:
                        "You do not have permission to use wildcard mentions in this stream.",
                }),
            );
            return false;
        }
        if (
            user_acknowledged_all_everyone === undefined ||
            user_acknowledged_all_everyone === false
        ) {
            // user has not seen a warning message yet if undefined
            show_all_everyone_warnings(stream_id);
            $("#compose-send-button").prop("disabled", false);
            $("#sending-indicator").hide();
            return false;
        }
    } else {
        // the message no longer contains @all or @everyone
        clear_all_everyone_warnings();
    }
    // at this point, the user has either acknowledged the warning or removed @all / @everyone
    user_acknowledged_all_everyone = undefined;
    return true;
}
function validate_stream_message_announce(sub) {
    const stream_count = peer_data.get_subscriber_count(sub.stream_id) || 0;
    if (sub.name === "announce" && stream_count > announce_warn_threshold) {
        if (user_acknowledged_announce === undefined || user_acknowledged_announce === false) {
            // user has not seen a warning message yet if undefined
            show_announce_warnings(sub.stream_id);
            $("#compose-send-button").prop("disabled", false);
            $("#sending-indicator").hide();
            return false;
        }
    } else {
        clear_announce_warnings();
    }
    // at this point, the user has acknowledged the warning
    user_acknowledged_announce = undefined;
    return true;
}
function validate_stream_message_post_policy(sub) {
    if (page_params.is_admin) {
        return true;
    }
    const stream_post_permission_type = stream_data.stream_post_policy_values;
    const stream_post_policy = sub.stream_post_policy;
    if (stream_post_policy === stream_post_permission_type.admins.code) {
        compose_error.show(
            $t_html({
                defaultMessage: "Only organization admins are allowed to post to this stream.",
            }),
        );
        return false;
    }
    if (page_params.is_moderator) {
        return true;
    }
    if (stream_post_policy === stream_post_permission_type.moderators.code) {
        compose_error.show(
            $t_html({
                defaultMessage:
                    "Only organization admins and moderators are allowed to post to this stream.",
            }),
        );
        return false;
    }
    if (page_params.is_guest && stream_post_policy !== stream_post_permission_type.everyone.code) {
        compose_error.show(
            $t_html({defaultMessage: "Guests are not allowed to post to this stream."}),
        );
        return false;
    }
    const person = people.get_by_user_id(page_params.user_id);
    const current_datetime = new Date(Date.now());
    const person_date_joined = new Date(person.date_joined);
    const days = (current_datetime - person_date_joined) / 1000 / 86400;
    let error_html;
    if (
        stream_post_policy === stream_post_permission_type.non_new_members.code &&
        days < page_params.realm_waiting_period_threshold
    ) {
        error_html = $t_html(
            {
                defaultMessage:
                    "New members are not allowed to post to this stream.
Permission will be granted in {days} days.",
            },
            {days},
        );
        compose_error.show(error_html);
        return false;
    }
    return true;
}
export function validation_error(error_type, stream_name) {
    let response;
    switch (error_type) {
        case "does-not-exist":
            response = $t_html(
                {
                    defaultMessage:
                        "
The stream {stream_name} does not exist.
Manage your subscriptions