import ClipboardJS from "clipboard";
import $ from "jquery";

import * as resolved_topic from "../shared/js/resolved_topic";
import render_all_messages_sidebar_actions from "../templates/all_messages_sidebar_actions.hbs";
import render_delete_topic_modal from "../templates/confirm_dialog/confirm_delete_topic.hbs";
import render_drafts_sidebar_actions from "../templates/drafts_sidebar_action.hbs";
import render_move_topic_to_stream from "../templates/move_topic_to_stream.hbs";
import render_starred_messages_sidebar_actions from "../templates/starred_messages_sidebar_actions.hbs";
import render_stream_sidebar_actions from "../templates/stream_sidebar_actions.hbs";
import render_topic_sidebar_actions from "../templates/topic_sidebar_actions.hbs";

import * as blueslip from "./blueslip";
import * as browser_history from "./browser_history";
import * as channel from "./channel";
import * as compose_actions from "./compose_actions";
import * as confirm_dialog from "./confirm_dialog";
import * as dialog_widget from "./dialog_widget";
import * as drafts from "./drafts";
import {DropdownListWidget} from "./dropdown_list_widget";
import * as hash_util from "./hash_util";
import {$t, $t_html} from "./i18n";
import * as message_edit from "./message_edit";
import * as muted_topics from "./muted_topics";
import * as muted_topics_ui from "./muted_topics_ui";
import {page_params} from "./page_params";
import * as popovers from "./popovers";
import * as resize from "./resize";
import * as settings_data from "./settings_data";
import * as starred_messages from "./starred_messages";
import * as starred_messages_ui from "./starred_messages_ui";
import * as stream_bar from "./stream_bar";
import * as stream_color from "./stream_color";
import * as stream_data from "./stream_data";
import * as stream_settings_ui from "./stream_settings_ui";
import * as sub_store from "./sub_store";
import * as ui_report from "./ui_report";
import * as unread_ops from "./unread_ops";
import {user_settings} from "./user_settings";

// We handle stream popovers and topic popovers in this
// module.  Both are popped up from the left sidebar.
let current_stream_sidebar_elem;
let current_topic_sidebar_elem;
let all_messages_sidebar_elem;
let starred_messages_sidebar_elem;
let drafts_sidebar_elem;
let stream_widget;
let $stream_header_colorblock;

function get_popover_menu_items(sidebar_elem) {
    if (!sidebar_elem) {
        blueslip.error("Trying to get menu items when action popover is closed.");
        return undefined;
    }

    const popover_data = $(sidebar_elem).data("popover");
    if (!popover_data) {
        blueslip.error("Cannot find popover data for stream sidebar menu.");
        return undefined;
    }
    return $("li:not(.divider):visible > a", popover_data.$tip);
}

export function stream_sidebar_menu_handle_keyboard(key) {
    const items = get_popover_menu_items(current_stream_sidebar_elem);
    popovers.popover_items_handle_keyboard(key, items);
}

export function topic_sidebar_menu_handle_keyboard(key) {
    const items = get_popover_menu_items(current_topic_sidebar_elem);
    popovers.popover_items_handle_keyboard(key, items);
}

export function all_messages_sidebar_menu_handle_keyboard(key) {
    const items = get_popover_menu_items(all_messages_sidebar_elem);
    popovers.popover_items_handle_keyboard(key, items);
}

export function starred_messages_sidebar_menu_handle_keyboard(key) {
    const items = get_popover_menu_items(starred_messages_sidebar_elem);
    popovers.popover_items_handle_keyboard(key, items);
}

function elem_to_stream_id($elem) {
    const stream_id = Number.parseInt($elem.attr("data-stream-id"), 10);

    if (stream_id === undefined) {
        blueslip.error("could not find stream id");
    }

    return stream_id;
}

function topic_popover_stream_id(e) {
    return elem_to_stream_id($(e.currentTarget));
}

export function stream_popped() {
    return current_stream_sidebar_elem !== undefined;
}

export function topic_popped() {
    return current_topic_sidebar_elem !== undefined;
}

export function all_messages_popped() {
    return all_messages_sidebar_elem !== undefined;
}

export function starred_messages_popped() {
    return starred_messages_sidebar_elem !== undefined;
}

export function drafts_popped() {
    return drafts_sidebar_elem !== undefined;
}

export function hide_stream_popover() {
    if (stream_popped()) {
        $(current_stream_sidebar_elem).popover("destroy");
        current_stream_sidebar_elem = undefined;
    }
}

export function hide_topic_popover() {
    if (topic_popped()) {
        $(current_topic_sidebar_elem).popover("destroy");
        current_topic_sidebar_elem = undefined;
    }
}

export function hide_all_messages_popover() {
    if (all_messages_popped()) {
        $(all_messages_sidebar_elem).popover("destroy");
        all_messages_sidebar_elem = undefined;
    }
}

export function hide_starred_messages_popover() {
    if (starred_messages_popped()) {
        $(starred_messages_sidebar_elem).popover("destroy");
        starred_messages_sidebar_elem = undefined;
    }
}

export function hide_drafts_popover() {
    if (drafts_popped()) {
        $(drafts_sidebar_elem).popover("destroy");
        drafts_sidebar_elem = undefined;
    }
}

// These are the only two functions that is really shared by the
// two popovers, so we could split out topic stuff to
// another module pretty easily.
export function show_streamlist_sidebar() {
    $(".app-main .column-left").addClass("expanded");
    resize.resize_page_components();
}

export function hide_streamlist_sidebar() {
    $(".app-main .column-left").removeClass("expanded");
}

function stream_popover_sub(e) {
    const $elem = $(e.currentTarget).parents("ul");
    const stream_id = elem_to_stream_id($elem);
    const sub = sub_store.get(stream_id);
    if (!sub) {
        blueslip.error("Unknown stream: " + stream_id);
        return undefined;
    }
    return sub;
}

// This little function is a workaround for the fact that
// Bootstrap popovers don't properly handle being resized --
// so after resizing our popover to add in the spectrum color
// picker, we need to adjust its height accordingly.
function update_spectrum($popover, update_func) {
    const initial_height = $popover[0].offsetHeight;

    const $colorpicker = $popover.find(".colorpicker-container").find(".colorpicker");
    update_func($colorpicker);
    const after_height = $popover[0].offsetHeight;

    const $popover_root = $popover.closest(".popover");
    const current_top_px = Number.parseFloat($popover_root.css("top").replace("px", ""));
    const height_delta = after_height - initial_height;
    let top = current_top_px - height_delta / 2;

    if (top < 0) {
        top = 0;
        $popover_root.find("div.arrow").hide();
    } else if (top + after_height > $(window).height() - 20) {
        top = $(window).height() - after_height - 20;
        if (top < 0) {
            top = 0;
        }
        $popover_root.find("div.arrow").hide();
    }

    $popover_root.css("top", top + "px");
}

// Builds the `Copy link to topic` topic action.
function build_topic_link_clipboard(url) {
    if (!url) {
        return;
    }

    const copy_event = new ClipboardJS(".sidebar-popover-copy-link-to-topic", {
        text() {
            return url;
        },
    });

    // Hide the topic popover once the url is successfully
    // copied to clipboard.
    copy_event.on("success", () => {
        hide_topic_popover();
    });
}

function build_stream_popover(opts) {
    const elt = opts.elt;
    const stream_id = opts.stream_id;

    if (stream_popped() && current_stream_sidebar_elem === elt) {
        // If the popover is already shown, clicking again should toggle it.
        hide_stream_popover();
        return;
    }

    popovers.hide_all();
    show_streamlist_sidebar();

    const content = render_stream_sidebar_actions({
        stream: sub_store.get(stream_id),
    });

    $(elt).popover({
        content,
        html: true,
        trigger: "manual",
        fixed: true,
        fix_positions: true,
    });

    $(elt).popover("show");
    const $popover = $(`.streams_popover[data-stream-id="${CSS.escape(stream_id)}"]`);

    update_spectrum($popover, ($colorpicker) => {
        $colorpicker.spectrum(stream_color.sidebar_popover_colorpicker_options);
    });

    current_stream_sidebar_elem = elt;
}

function build_topic_popover(opts) {
    const elt = opts.elt;
    const stream_id = opts.stream_id;
    const topic_name = opts.topic_name;

    if (topic_popped() && current_topic_sidebar_elem === elt) {
        // If the popover is already shown, clicking again should toggle it.
        hide_topic_popover();
        return;
    }

    const sub = sub_store.get(stream_id);
    if (!sub) {
        blueslip.error("cannot build topic popover for stream: " + stream_id);
        return;
    }

    popovers.hide_all();
    show_streamlist_sidebar();

    const topic_muted = muted_topics.is_topic_muted(sub.stream_id, topic_name);
    const has_starred_messages = starred_messages.get_count_in_topic(sub.stream_id, topic_name) > 0;
    // Arguably, we could offer the "Move topic" option even if users
    // can only edit the name within a stream.
    const can_move_topic = settings_data.user_can_move_messages_between_streams();

    const content = render_topic_sidebar_actions({
        stream_name: sub.name,
        stream_id: sub.stream_id,
        topic_name,
        topic_muted,
        can_move_topic,
        is_realm_admin: page_params.is_admin,
        topic_is_resolved: resolved_topic.is_resolved(topic_name),
        color: sub.color,
        has_starred_messages,
    });

    $(elt).popover({
        content,
        html: true,
        trigger: "manual",
        fixed: true,
    });

    $(elt).popover("show");

    current_topic_sidebar_elem = elt;
}

function build_all_messages_popover(e) {
    const elt = e.target;

    if (all_messages_popped() && all_messages_sidebar_elem === elt) {
        hide_all_messages_popover();
        e.stopPropagation();
        return;
    }

    popovers.hide_all();
    show_streamlist_sidebar();

    const content = render_all_messages_sidebar_actions();

    $(elt).popover({
        content,
        html: true,
        trigger: "manual",
        fixed: true,
    });

    $(elt).popover("show");
    all_messages_sidebar_elem = elt;
    e.stopPropagation();
}

function build_starred_messages_popover(e) {
    const elt = e.target;

    if (starred_messages_popped() && starred_messages_sidebar_elem === elt) {
        hide_starred_messages_popover();
        e.stopPropagation();
        return;
    }

    popovers.hide_all();
    show_streamlist_sidebar();

    const show_unstar_all_button = starred_messages.get_count() > 0;
    const content = render_starred_messages_sidebar_actions({
        show_unstar_all_button,
        starred_message_counts: user_settings.starred_message_counts,
    });

    $(elt).popover({
        content,
        html: true,
        trigger: "manual",
        fixed: true,
    });

    $(elt).popover("show");
    starred_messages_sidebar_elem = elt;
    e.stopPropagation();
}

function build_drafts_popover(e) {
    const elt = e.target;

    if (drafts_popped() && drafts_sidebar_elem === elt) {
        hide_drafts_popover();
        e.stopPropagation();
        return;
    }

    popovers.hide_all();
    show_streamlist_sidebar();
    const content = render_drafts_sidebar_actions({});
    $(elt).popover({
        content,
        html: true,
        trigger: "manual",
        fixed: true,
    });

    $(elt).popover("show");
    drafts_sidebar_elem = elt;
    e.stopPropagation();
}

function build_move_topic_to_stream_popover(e, current_stream_id, topic_name) {
    // TODO: Add support for keyboard-alphabet navigation. Some orgs
    // many streams and scrolling can be a painful process in that
    // case.
    //
    // NOTE: Private streams are also included in this list.  We
    // likely will make it possible to move messages to/from private
    // streams in the future.
    const current_stream_name = stream_data.maybe_get_stream_name(current_stream_id);
    const args = {
        topic_name,
        current_stream_id,
        notify_new_thread: message_edit.notify_new_thread_default,
        notify_old_thread: message_edit.notify_old_thread_default,
    };

    hide_topic_popover();

    function get_params_from_form() {
        return Object.fromEntries(
            $("#move_topic_form")
                .serializeArray()
                .map(({name, value}) => [name, value]),
        );
    }

    function update_submit_button_disabled_state(select_stream_id) {
        const {current_stream_id, new_topic_name, old_topic_name} = get_params_from_form();

        // Unlike most topic comparisons in Zulip, we intentionally do
        // a case-sensitive comparison, since adjusting the
        // capitalization of a topic is a valid operation.
        $("#move_topic_modal .dialog_submit_button")[0].disabled =
            Number.parseInt(current_stream_id, 10) === Number.parseInt(select_stream_id, 10) &&
            new_topic_name.trim() === old_topic_name.trim();
    }

    function move_topic() {
        const params = get_params_from_form();

        const {old_topic_name} = params;
        const select_stream_id = stream_widget.value();

        let {
            current_stream_id,
            new_topic_name,
            send_notification_to_new_thread,
            send_notification_to_old_thread,
        } = params;
        new_topic_name = new_topic_name.trim();
        send_notification_to_new_thread = send_notification_to_new_thread === "on";
        send_notification_to_old_thread = send_notification_to_old_thread === "on";
        current_stream_id = Number.parseInt(current_stream_id, 10);

        dialog_widget.show_dialog_spinner();
        message_edit.with_first_message_id(
            current_stream_id,
            old_topic_name,
            (message_id) => {
                if (old_topic_name.trim() === new_topic_name.trim()) {
                    // We use `undefined` to tell the server that
                    // there has been no change in the topic name.
                    new_topic_name = undefined;
                }

                if (old_topic_name && select_stream_id) {
                    message_edit.move_topic_containing_message_to_stream(
                        message_id,
                        select_stream_id,
                        new_topic_name,
                        send_notification_to_new_thread,
                        send_notification_to_old_thread,
                    );
                }
            },
            (xhr) => {
                dialog_widget.hide_dialog_spinner();
                ui_report.error(
                    $t_html({defaultMessage: "Error moving topic"}),
                    xhr,
                    $("#move_topic_modal #dialog_error"),
                );
            },
        );
    }

    function move_topic_post_render() {
        $stream_header_colorblock = $("#dialog_widget_modal .topic_stream_edit_header").find(
            ".stream_header_colorblock",
        );
        stream_bar.decorate(current_stream_name, $stream_header_colorblock, false);
        const streams_list = stream_data.subscribed_subs().map((stream) => ({
            name: stream.name,
            value: stream.stream_id.toString(),
        }));
        const opts = {
            widget_name: "select_stream",
            data: streams_list,
            default_text: $t({defaultMessage: "No streams"}),
            include_current_item: false,
            value: current_stream_id,
            on_update: update_submit_button_disabled_state,
        };
        stream_widget = new DropdownListWidget(opts);
        stream_widget.setup();

        update_submit_button_disabled_state(stream_widget.value());
        $("#move_topic_modal .inline_topic_edit").on("input", () => {
            update_submit_button_disabled_state(stream_widget.value());
        });
    }

    dialog_widget.launch({
        html_heading: $t_html({defaultMessage: "Move topic"}),
        html_body: render_move_topic_to_stream(args),
        html_submit_button: $t_html({defaultMessage: "Confirm"}),
        id: "move_topic_modal",
        on_click: move_topic,
        loading_spinner: true,
        post_render: move_topic_post_render,
    });
}

export function register_click_handlers() {
    $("#stream_filters").on("click", ".stream-sidebar-menu-icon", (e) => {
        e.stopPropagation();

        const elt = e.target;
        const $stream_li = $(elt).parents("li");
        const stream_id = elem_to_stream_id($stream_li);

        build_stream_popover({
            elt,
            stream_id,
        });
    });

    $("#stream_filters").on("click", ".topic-sidebar-menu-icon", (e) => {
        e.stopPropagation();

        const elt = $(e.target).closest(".topic-sidebar-menu-icon").expectOne()[0];
        const $stream_li = $(elt).closest(".narrow-filter").expectOne();
        const stream_id = elem_to_stream_id($stream_li);
        const topic_name = $(elt).closest("li").expectOne().attr("data-topic-name");
        const url = $(elt).closest("li").find(".topic-name").expectOne().prop("href");

        build_topic_popover({
            elt,
            stream_id,
            topic_name,
        });

        build_topic_link_clipboard(url);
    });

    $("#global_filters").on("click", ".all-messages-sidebar-menu-icon", build_all_messages_popover);

    $("#global_filters").on(
        "click",
        ".starred-messages-sidebar-menu-icon",
        build_starred_messages_popover,
    );

    $("#global_filters").on("click", ".drafts-sidebar-menu-icon", build_drafts_popover);

    $("body").on("click keypress", ".move-topic-dropdown .list_item", (e) => {
        // We want the dropdown to collapse once any of the list item is pressed
        // and thus don't want to kill the natural bubbling of event.
        e.preventDefault();

        if (e.type === "keypress" && e.key !== "Enter") {
            return;
        }
        const stream_name = stream_data.maybe_get_stream_name(
            Number.parseInt(stream_widget.value(), 10),
        );

        stream_bar.decorate(stream_name, $stream_header_colorblock, false);
    });

    register_stream_handlers();
    register_topic_handlers();
}

export function register_stream_handlers() {
    // Stream settings
    $("body").on("click", ".open_stream_settings", (e) => {
        const sub = stream_popover_sub(e);
        hide_stream_popover();

        const stream_edit_hash = hash_util.stream_edit_url(sub);
        browser_history.go_to_location(stream_edit_hash);
    });

    // Pin/unpin
    $("body").on("click", ".pin_to_top", (e) => {
        const sub = stream_popover_sub(e);
        hide_stream_popover();
        stream_settings_ui.toggle_pin_to_top_stream(sub);
        e.stopPropagation();
    });

    // Mark all messages in stream as read
    $("body").on("click", ".mark_stream_as_read", (e) => {
        const sub = stream_popover_sub(e);
        hide_stream_popover();
        unread_ops.mark_stream_as_read(sub.stream_id);
        e.stopPropagation();
    });

    // Mark all messages as read
    $("body").on("click", "#mark_all_messages_as_read", (e) => {
        hide_all_messages_popover();
        unread_ops.mark_all_as_read();
        e.stopPropagation();
    });

    // Unstar all messages
    $("body").on("click", "#unstar_all_messages", (e) => {
        hide_starred_messages_popover();
        e.preventDefault();
        e.stopPropagation();
        starred_messages_ui.confirm_unstar_all_messages();
    });

    $("body").on("click", "#delete_all_drafts_sidebar", (e) => {
        hide_drafts_popover();
        e.stopPropagation();
        drafts.confirm_delete_all_drafts();
    });

    // Unstar all messages in topic
    $("body").on("click", ".sidebar-popover-unstar-all-in-topic", (e) => {
        e.preventDefault();
        e.stopPropagation();
        const topic_name = $(".sidebar-popover-unstar-all-in-topic").attr("data-topic-name");
        const stream_id = $(".sidebar-popover-unstar-all-in-topic").attr("data-stream-id");
        hide_topic_popover();
        starred_messages_ui.confirm_unstar_all_messages_in_topic(
            Number.parseInt(stream_id, 10),
            topic_name,
        );
    });

    // Toggle displaying starred message count
    $("body").on("click", "#toggle_display_starred_msg_count", (e) => {
        hide_starred_messages_popover();
        e.preventDefault();
        e.stopPropagation();
        const starred_msg_counts = user_settings.starred_message_counts;
        const data = {};
        data.starred_message_counts = JSON.stringify(!starred_msg_counts);
        channel.patch({
            url: "/json/settings",
            data,
        });
    });
    // Mute/unmute
    $("body").on("click", ".toggle_stream_muted", (e) => {
        const sub = stream_popover_sub(e);
        hide_stream_popover();
        stream_settings_ui.set_muted(sub, !sub.is_muted);
        e.stopPropagation();
    });

    // New topic in stream menu
    $("body").on("click", ".popover_new_topic_button", (e) => {
        const sub = stream_popover_sub(e);
        hide_stream_popover();

        compose_actions.start("stream", {
            trigger: "popover new topic button",
            stream: sub.name,
            topic: "",
        });
        e.preventDefault();
        e.stopPropagation();
    });

    // Unsubscribe
    $("body").on("click", ".popover_sub_unsub_button", function (e) {
        $(this).toggleClass("unsub");
        $(this).closest(".popover").fadeOut(500).delay(500).remove();

        const sub = stream_popover_sub(e);
        stream_settings_ui.sub_or_unsub(sub);
        e.preventDefault();
        e.stopPropagation();
    });

    // Choose a different color.
    $("body").on("click", ".choose_stream_color", (e) => {
        update_spectrum($(e.target).closest(".streams_popover"), ($colorpicker) => {
            $(".colorpicker-container").show();
            $colorpicker.spectrum("destroy");
            $colorpicker.spectrum(stream_color.sidebar_popover_colorpicker_options_full);
            // In theory this should clean up the old color picker,
            // but this seems a bit flaky -- the new colorpicker
            // doesn't fire until you click a button, but the buttons
            // have been hidden.  We work around this by just manually
            // fixing it up here.
            $colorpicker.parent().find(".sp-container").removeClass("sp-buttons-disabled");
            $(e.target).hide();
        });

        $(".streams_popover").on("click", "a.sp-cancel", () => {
            hide_stream_popover();
        });
        if ($(window).width() <= 768) {
            $(".popover-inner").hide().fadeIn(300);
            $(".popover").addClass("colorpicker-popover");
        }
    });
}

export function register_topic_handlers() {
    // Mute the topic
    $("body").on("click", ".sidebar-popover-mute-topic", (e) => {
        const stream_id = topic_popover_stream_id(e);
        if (!stream_id) {
            return;
        }

        const topic = $(e.currentTarget).attr("data-topic-name");
        muted_topics_ui.mute_topic(stream_id, topic);
        e.stopPropagation();
        e.preventDefault();
    });

    // Unmute the topic
    $("body").on("click", ".sidebar-popover-unmute-topic", (e) => {
        const stream_id = topic_popover_stream_id(e);
        if (!stream_id) {
            return;
        }

        const topic = $(e.currentTarget).attr("data-topic-name");
        muted_topics_ui.unmute_topic(stream_id, topic);
        e.stopPropagation();
        e.preventDefault();
    });

    // Mark all messages as read
    $("body").on("click", ".sidebar-popover-mark-topic-read", (e) => {
        const stream_id = topic_popover_stream_id(e);
        if (!stream_id) {
            return;
        }

        const topic = $(e.currentTarget).attr("data-topic-name");
        hide_topic_popover();
        unread_ops.mark_topic_as_read(stream_id, topic);
        e.stopPropagation();
    });

    // Deleting all message in a topic
    $("body").on("click", ".sidebar-popover-delete-topic-messages", (e) => {
        const stream_id = topic_popover_stream_id(e);
        if (!stream_id) {
            return;
        }

        const topic = $(e.currentTarget).attr("data-topic-name");
        const args = {
            topic_name: topic,
        };

        hide_topic_popover();

        const html_body = render_delete_topic_modal(args);

        confirm_dialog.launch({
            html_heading: $t_html({defaultMessage: "Delete topic"}),
            help_link: "/help/delete-a-topic",
            html_body,
            on_click: () => {
                message_edit.delete_topic(stream_id, topic);
            },
        });

        e.stopPropagation();
    });

    $("body").on("click", ".sidebar-popover-toggle-resolved", (e) => {
        const $topic_row = $(e.currentTarget);
        const stream_id = Number.parseInt($topic_row.attr("data-stream-id"), 10);
        const topic_name = $topic_row.attr("data-topic-name");
        message_edit.with_first_message_id(stream_id, topic_name, (message_id) => {
            message_edit.toggle_resolve_topic(message_id, topic_name);
        });

        hide_topic_popover();
        e.stopPropagation();
        e.preventDefault();
    });

    $("body").on("click", ".sidebar-popover-move-topic-messages", (e) => {
        const $topic_row = $(e.currentTarget);
        const stream_id = Number.parseInt($topic_row.attr("data-stream-id"), 10);
        const topic_name = $topic_row.attr("data-topic-name");
        build_move_topic_to_stream_popover(e, stream_id, topic_name);
        e.stopPropagation();
        e.preventDefault();
    });
}
