<reponame>inpprenable/RustyBot
import discord
from discord.ext import commands
from .utils.dataIO import fileIO
from cogs.utils.dataIO import dataIO
from datetime import datetime
from copy import deepcopy
from .utils import checks
from __main__ import send_cmd_help
# Sys
import aiohttp
import random
import os
import sys
import requests

DIR_DATA = "data/oboobs"
SETTINGS = DIR_DATA + "/settings.json"


# API info:
# example: "/boobs/10/20/rank/" - get 20 boobs elements, start from 10th ordered by rank; noise: "/noise/{count=1; sql limit}/",
# example: "/noise/50/" - get 50 random noise elements; model search: "/boobs/model/{model; sql ilike}/",
# example: "/boobs/model/something/" - get all boobs elements, where model name contains "something", ordered by id; author search: "/boobs/author/{author; sql ilike}/",
# example: "/boobs/author/something/" - get all boobs elements, where author name contains "something", ordered by id; get boobs by id: "/boobs/get/{id=0}/",
# example: "/boobs/get/6202/" - get boobs element with id 6202; get boobs count: "/boobs/count/"; get noise count: "/noise/count/"; vote for boobs: "/boobs/vote/{id=0}/{operation=plus;[plus,minus]}/",
# example: "/boobs/vote/6202/minus/" - negative vote for boobs with id 6202; vote for noise: "/noise/vote/{id=0}/{operation=plus;[plus,minus]}/",
# example: "/noise/vote/57/minus/" - negative vote for noise with id 57;

# example: "/butts/10/20/rank/" - get 20 butts elements, start from 10th ordered by rank; noise: "/noise/{count=1; sql limit}/",
# example: "/noise/50/" - get 50 random noise elements; model search: "/butts/model/{model; sql ilike}/",
# example: "/butts/model/something/" - get all butts elements, where model name contains "something", ordered by id; author search: "/butts/author/{author; sql ilike}/",
# example: "/butts/author/something/" - get all butts elements, where author name contains "something", ordered by id; get butts by id: "/butts/get/{id=0}/",
# example: "/butts/get/6202/" - get butts element with id 6202; get butts count: "/butts/count/"; get noise count: "/noise/count/"; vote for butts: "/butts/vote/{id=0}/{operation=plus;[plus,minus]}/",
# example: "/butts/vote/6202/minus/" - negative vote for butts with id 6202; vote for noise: "/noise/vote/{id=0}/{operation=plus;[plus,minus]}/",
# example: "/noise/vote/57/minus/" - negative vote for noise with id 57;

class BankError(Exception):
    pass


class AccountAlreadyExists(BankError):
    pass


class NoAccount(BankError):
    pass


class Statistique:
    def __init__(self, bot, file_path):
        self.accounts = dataIO.load_json(file_path)
        self.bot = bot

    def create_account(self, user):
        server = user.server
        if not self.account_exists(user):
            if server.id not in self.accounts:
                self.accounts[server.id] = {}
            if user.id in self.accounts:  # Legacy account      <-fort risque de bug
                Sboobs = self.accounts[user.id]["boobs"]
                Sass = self.accounts[user.id]["ass"]
                Shentai = self.accounts[user.id]["hentai"]
            else:
                Sboobs, Sass, Shentai = 0, 0, 0
            timestamp = datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S")
            account = {"name": user.name,
                       "boobs": Sboobs,
                       "ass": Sass,
                       "hentai": Shentai,
                       "created_at": timestamp
                       }
            self.accounts[server.id][user.id] = account
            self._save_bank()
            # return self.get_account(user)
        else:
            raise AccountAlreadyExists()

    def account_exists(self, user):
        try:
            self._get_account(user)
        except NoAccount:
            return False
        return True

    def _get_account(self, user):
        server = user.server
        try:
            return deepcopy(self.accounts[server.id][user.id])
        except KeyError:
            raise NoAccount()

    def _save_bank(self):
        dataIO.save_json("data/oboobs/statistique.json", self.accounts)

    def get_oboobs_tot(self, user):
        account = self._get_account(user)
        return account["boobs"] + account["ass"] + account["hentai"]

    def get_oboobs(self, user, Stype):  # Stype=boobs|ass|hentai
        account = self._get_account(user)
        return account[Stype]

    def get_max_oboobs(self, user):
        server = user.server
        try:
            max = 0
            theuser = None
            for other in self.accounts[server.id]:
                account = self.accounts[server.id][other]
                k = account["boobs"] + account["ass"] + account["hentai"]
                if k > max:
                    max = k
                    theuser = other
            if k == 0:
                raise NoAccount()
            return self.accounts[server.id][theuser]["name"]
        except:
            raise NoAccount()

    def up_oboobs(self, user, Stype):  # Stype=boobs|ass|hentai
        server = user.server
        if not self.account_exists(user):
            self.create_account(user)
        account = self._get_account(user)
        account[Stype] = account[Stype] + 1
        self.accounts[server.id][user.id] = account
        self._save_bank()

    def wipe_stat(self, server):
        self.accounts[server.id] = {}
        self._save_bank()

    def wipe_stat_perso(self, user):
        server = user.server
        if self.account_exists(user):
            temp_server_accounts = {}
            raw_server_accounts = deepcopy(self.accounts[server.id])
            for k in self.accounts[server.id]:
                if k != user.id:
                    temp_server_accounts[k] = self.accounts[server.id][k]
            self.accounts[server.id] = temp_server_accounts
            self._save_bank()


class oboobs:
    """The oboobs/obutts.ru NSFW pictures of nature cog.
    https://github.com/Canule/Mash-Cogs
    """

    def __init__(self, bot):
        self.bot = bot

        self.stat_class = Statistique(bot, "data/oboobs/statistique.json")
        self.settings = fileIO(SETTINGS, "load")

    @commands.group(name="oboobs", pass_context=True)
    async def _oboobs(self, ctx):
        """The oboobs/obutts.ru pictures of nature cog."""
        if ctx.invoked_subcommand is None:
            await send_cmd_help(ctx)
            return

    # Boobs
    @commands.command(pass_context=True, no_pm=False)
    async def boobs(self, ctx, *nb):
        """Shows some boobs."""
        author = ctx.message.author
        nsfwChan = False

        try:
            if nb == ():
                nb = 1
            else:
                nb = int(nb[0])
                nb = min(nb, 5)
        except Exception as e:
            nb = 1
        for a in self.settings["nsfw_channels"]:
            if a == ctx.message.channel.id:
                nsfwChan = True
                break
        try:
            if nsfwChan:
                if self.settings["nsfw_msg"]:
                    await self.bot.say("{}` Pas de ça ici cochon`".format(author.mention))
                    await self.bot.say("https://media.giphy.com/media/WUeeGwT8d8KFa/giphy.gif")
            else:
                for k in range(nb):
                    rdm = random.randint(0, 10219)
                    search = ("http://api.oboobs.ru/boobs/{}".format(rdm))
                    async with aiohttp.get(search) as r:
                        result = await r.json()
                        boob = random.choice(result)
                        boob = "http://media.oboobs.ru/{}".format(boob["preview"])
                        await self.bot.say("{}".format(boob))
                        if not ctx.message.channel.is_private:
                            self.stat_class.up_oboobs(author, "boobs")
        except Exception as e:
            await self.bot.say("{} ` Error getting results.`".format(author.mention))
            return

    # Hentai
    @commands.command(pass_context=True, no_pm=False)
    async def hentai(self, ctx, *tag):
        """Shows some hentai."""
        author = ctx.message.author
        nsfwChan = False
        for a in self.settings["nsfw_channels"]:
            if a == ctx.message.channel.id:
                nsfwChan = True
                break
        nmax = 100
        try:
            if tag == ():
                tag = 'nude'
            else:
                tag = tag[0]
            search = "https://danbooru.donmai.us/posts.xml?limit=" + str(nmax) + "&tags=" + tag
            r = requests.get(search)
            hentai = r.text
            size = len("<large-file-url>")
            total = hentai.count("<large-file-url>")
            if total == 0:
                await self.bot.say("pas de ça en stock")
                return
            rdm = random.randint(0, min(nmax, total) - 1)
            a, b = 0, 0
            for k in range(rdm + 1):
                a = hentai.index("<large-file-url>", a + size)
                b = hentai.index("</large-file-url>", b + size)
            hentai = hentai[a + size:b]
        except Exception as e:
            await self.bot.say("{} ` Error getting results.`".format(author.mention))
            return
        if not nsfwChan:
            await self.bot.say("{}".format(hentai))
            if not ctx.message.channel.is_private:
                self.stat_class.up_oboobs(author, "hentai")
        else:
            await self.bot.send_message(ctx.message.author, "{}".format(hentai))
            if self.settings["nsfw_msg"]:
                await self.bot.say("{}` Pas de ça ici cochon`".format(author.mention))
                await self.bot.say("http://giphy.com/gifs/mrw-hentai-rV8O58C2QWf4s")

    # Cat
    @commands.command(pass_context=True, no_pm=False)
    async def cat(self, ctx):
        """Shows some cats."""
        author = ctx.message.author
        search = ("http://thecatapi.com/api/images/get")
        try:
            async with aiohttp.get(search) as r:
                cat = r.url
            await self.bot.say(cat)
        except Exception as e:
            await self.bot.say("{} ` Error getting results.`".format(author.mention))
            return

    # Ass
    @commands.command(pass_context=True, no_pm=False)
    async def ass(self, ctx, *nb):
        """Shows some ass."""
        author = ctx.message.author
        nsfwChan = False
        try:
            if nb == ():
                nb = 1
            else:
                nb = int(nb[0])
                nb = min(nb, 5)
        except Exception as e:
            nb = 1
        for a in self.settings["nsfw_channels"]:
            if a == ctx.message.channel.id:
                nsfwChan = True
                break
        try:
            if nsfwChan:
                if self.settings["nsfw_msg"]:
                    await self.bot.say("{}` Pas de ça ici cochon`".format(author.mention))
                    await self.bot.say("https://media.giphy.com/media/qIFepMd1Dx0uQ/giphy.gif")
            else:
                for k in range(nb):
                    rdm = random.randint(0, 4155)
                    search = ("http://api.obutts.ru/butts/{}".format(rdm))
                    async with aiohttp.get(search) as r:
                        result = await r.json()
                        ass = random.choice(result)
                        ass = "http://media.obutts.ru/{}".format(ass["preview"])
                        await self.bot.say("{}".format(ass))
                        if not ctx.message.channel.is_private:
                            self.stat_class.up_oboobs(author, "ass")
        except Exception as e:
            await self.bot.say("{} ` Error getting results.`".format(author.mention))
            return

    # stat
    @commands.command(pass_context=True, no_pm=False)
    async def stat(self, ctx, user: discord.Member, *tag):
        """Show some stats."""
        author = ctx.message.author
        try:
            if self.stat_class.account_exists(user):
                if len(tag) != 0 and (tag[0] in ["boobs", "ass", "hentai"]):
                    await self.bot.say(
                        "{} a utilisé {} {} fois".format(user.name, tag[0], self.stat_class.get_oboobs(user, tag[0])))
                else:
                    await self.bot.say(
                        "{} a affiché {} truc cochons au total".format(user.name, self.stat_class.get_oboobs_tot(user)))
            else:
                await self.bot.say("{} est encore vierge de ce Discord".format(user.name))
        except Exception as e:
            await self.bot.say("erreur :{}".format(e))

    # stats
    @commands.command(pass_context=True, no_pm=False)
    async def stats(self, ctx):
        """Show the Pervert Master."""
        author = ctx.message.author
        try:
            sortie = self.stat_class.get_max_oboobs(author)
            await self.bot.say("{} est le plus grand pervers de ce Discord".format(sortie))
        except NoAccount:
            await self.bot.say("Toutes les âmes ici-bas sont pûres")

    # reset
    @checks.admin_or_permissions(manage_server=True)
    @_oboobs.command(pass_context=True, no_pm=False)
    async def reStat(self, ctx, user: discord.Member):
        """Navifation InPrivate"""
        author = ctx.message.author
        try:
            self.stat_class.wipe_stat_perso(user)
        except Exception as e:
            await self.bot.say(e)
        await self.bot.say("Et un puceau de plus dans ce Discord")

    @checks.admin_or_permissions(manage_server=True)
    @_oboobs.command(pass_context=True, no_pm=False)
    async def nsfw(self, ctx):
        """Toggle oboobs nswf for this channel on/off.
        Admin/owner restricted."""
        user = ctx.message.author
        nsfwChan = None
        # Reset nsfw.
        for a in self.settings["nsfw_channels"]:
            if a == ctx.message.channel.id:
                nsfwChan = True
                self.settings["nsfw_channels"].remove(a)
                await self.bot.say("{} ` nsfw ON`".format(user.mention))
                break
        # Set nsfw.
        if not nsfwChan:
            if ctx.message.channel not in self.settings["nsfw_channels"]:
                self.settings["nsfw_channels"].append(ctx.message.channel.id)
                await self.bot.say("{} ` nsfw OFF`".format(user.mention))
        fileIO(SETTINGS, "save", self.settings)

    @checks.admin_or_permissions(manage_server=True)
    @_oboobs.command(pass_context=True, no_pm=False)
    async def togglemsg(self, ctx):
        """Enable/Disable the oboobs nswf not allowed message
        Admin/owner restricted."""
        user = ctx.message.author
        # Toggle
        if self.settings["nsfw_msg"]:
            self.settings["nsfw_msg"] = False
            await self.bot.say("{} ` DM nsfw channel msg is now: Disabled.`".format(user.mention))
        elif not self.settings["nsfw_msg"]:
            self.settings["nsfw_msg"] = True
            await self.bot.say("{} ` DM nsfw channel msg is now: Enabled.`".format(user.mention))
        fileIO(SETTINGS, "save", self.settings)


def check_folders():
    if not os.path.exists(DIR_DATA):
        print("Creating data/oboobs folder...")
        os.makedirs(DIR_DATA)


def check_files():
    settings = {"nsfw_channels": ["133251234164375552"],
                "nsfw_msg": True}  # Red's testing chan. nsfw content off by default.

    if not fileIO(SETTINGS, "check"):
        print("Creating settings.json")
        fileIO(SETTINGS, "save", settings)

    f = "data/oboobs/statistique.json"
    if not dataIO.is_valid_json(f):
        print("Creating empty bank.json...")
        dataIO.save_json(f, {})


def setup(bot):
    check_folders()
    check_files()
    bot.add_cog(oboobs(bot))
