#include "ChatLink.h"

#include <codecvt>
#include <regex>

#include "Bancho.h"
#include "Lobby.h"
#include "MainMenu.h"
#include "NotificationOverlay.h"
#include "Osu.h"
#include "RoomScreen.h"
#include "SongBrowser/SongBrowser.h"
#include "TooltipOverlay.h"
#include "UIUserContextMenu.h"

ChatLink::ChatLink(float xPos, float yPos, float xSize, float ySize, UString link, UString label)
    : CBaseUILabel(xPos, yPos, xSize, ySize, link, label) {
    m_link = link;
    setDrawFrame(false);
    setDrawBackground(true);
    setBackgroundColor(0xff2e3784);
}

void ChatLink::mouse_update(bool *propagate_clicks) {
    CBaseUILabel::mouse_update(propagate_clicks);

    if(isMouseInside()) {
        osu->getTooltipOverlay()->begin();
        osu->getTooltipOverlay()->addLine(UString::format("link: %s", m_link.toUtf8()));
        osu->getTooltipOverlay()->end();

        setBackgroundColor(0xff3d48ac);
    } else {
        setBackgroundColor(0xff2e3784);
    }
}

void ChatLink::open_beatmap_link(i32 map_id, i32 set_id) {
    if(osu->getSongBrowser()->isVisible()) {
        osu->getSongBrowser()->map_autodl = map_id;
        osu->getSongBrowser()->set_autodl = set_id;
    } else if(osu->getMainMenu()->isVisible()) {
        osu->toggleSongBrowser();
        osu->getSongBrowser()->map_autodl = map_id;
        osu->getSongBrowser()->set_autodl = set_id;
    } else {
        env->openURLInDefaultBrowser(m_link);
    }
}

void ChatLink::onMouseUpInside() {
    std::string link_str = m_link.toUtf8();
    std::smatch match;

    // This lazy escaping is only good for endpoint URLs, not anything more serious
    UString escaped_endpoint;
    for(int i = 0; i < bancho.endpoint.length(); i++) {
        if(bancho.endpoint[i] == L'.') {
            escaped_endpoint.append("\\.");
        } else {
            escaped_endpoint.append(bancho.endpoint[i]);
        }
    }

    // Detect multiplayer invite links
    if(m_link.startsWith("osump://")) {
        if(osu->m_room->isVisible()) {
            osu->getNotificationOverlay()->addNotification("You are already in a multiplayer room.");
            return;
        }

        // If the password has a space in it, parsing will break, but there's no way around it...
        // osu!stable also considers anything after a space to be part of the lobby title :(
        std::regex_search(link_str, match, std::regex("osump://(\\d+)/(\\S*)"));
        u32 invite_id = strtoul(match.str(1).c_str(), NULL, 10);
        UString password = match.str(2).c_str();
        osu->m_lobby->joinRoom(invite_id, password);
        return;
    }

    // Detect user links
    // https:\/\/(osu\.)?akatsuki\.gg\/u(sers)?\/(\d+)
    UString user_pattern = "https://(osu\\.)?";
    user_pattern.append(escaped_endpoint);
    user_pattern.append("/u(sers)?/(\\d+)");
    if(std::regex_search(link_str, match, std::regex(user_pattern.toUtf8()))) {
        i32 user_id = std::stoi(match.str(3));
        osu->m_user_actions->open(user_id);
        return;
    }

    // Detect beatmap links
    // https:\/\/((osu\.)?akatsuki\.gg|osu\.ppy\.sh)\/b(eatmaps)?\/(\d+)
    UString map_pattern = "https://((osu\\.)?";
    map_pattern.append(escaped_endpoint);
    map_pattern.append("|osu\\.ppy\\.sh)/b(eatmaps)?/(\\d+)");
    if(std::regex_search(link_str, match, std::regex(map_pattern.toUtf8()))) {
        i32 map_id = std::stoi(match.str(4));
        open_beatmap_link(map_id, 0);
        return;
    }

    // Detect beatmapset links
    // https:\/\/((osu\.)?akatsuki\.gg|osu\.ppy\.sh)\/beatmapsets\/(\d+)(#osu\/(\d+))?
    UString set_pattern = "https://((osu\\.)?";
    set_pattern.append(escaped_endpoint);
    set_pattern.append("|osu\\.ppy\\.sh)/beatmapsets/(\\d+)(#osu/(\\d+))?");
    if(std::regex_search(link_str, match, std::regex(set_pattern.toUtf8()))) {
        i32 set_id = std::stoi(match.str(3));
        i32 map_id = 0;
        if(match[5].matched) {
            map_id = std::stoi(match.str(5));
        }

        open_beatmap_link(map_id, set_id);
        return;
    }

    env->openURLInDefaultBrowser(m_link);
}
