import logging
import praw
import random
import string
import time
from faker import Faker
from monobot import USER_AGENT
from monobot.exceptions import ConfigError


class MonoBot(object):
    def __init__(self, config, reddit=None):
        if "bot" not in config:
            raise ConfigError("Config must have a \"bot\" section.")
        if "thread" not in config["bot"]:
            raise ConfigError("Thread link must be provided in config")
        self._config = config
        self._logger = logging.getLogger("monobot")
        self._logger.setLevel(logging.DEBUG if config["bot"].get("verbose") else logging.INFO)
        self._r = reddit or self._build_reddit()
        try:
            self._thread = self._r.get_submission(config["bot"]["thread"])
        except (praw.errors.NotFound, praw.errors.InvalidSubreddit):
            raise ConfigError("Submission \"{}\" not found.".format(self._r.get_submission(config["bot"]["thread"])))
        self._logger.debug("Posting to thread: {}".format(self._thread.short_link))

    def _build_reddit(self):
        self._logger.debug("No reddit dependency given, using PRAW with UserAgent \"{}\"".format(USER_AGENT))
        r = praw.Reddit(user_agent=USER_AGENT)
        if self._config.get("oauth") and self._config["oauth"].get("id"):
            self._logger.debug("Using OAuth2 ID {}".format(self._config["oauth"]["id"]))
            try:
                r.set_oauth_app_info(client_id=self._config["oauth"]["id"],
                                     client_secret=self._config["oauth"]["secret"],
                                     redirect_uri=self._config["oauth"]["uri"])
                if "token" in self._config["oauth"]:
                    r.refresh_access_information(self._config["oauth"]["token"])
                elif "code" in self._config["oauth"]:
                    info = r.get_access_information(self._config["oauth"]["code"])
                    print("!!! OAuth2 Refresh Token: {}".format(info["refresh_token"]))
                else:
                    raise ConfigError("Code or token required for OAuth2")
            except praw.errors.OAuthInvalidGrant:
                raise ConfigError("Invalid OAuth2 code")
            self._logger.info("Logged in as {}".format(r.get_me()))
        elif self._config.get("credentials") and self._config["credentials"].get("username"):
            self._logger.debug("Using username {}".format(self._config["credentials"]["username"]))
            r.login(self._config["credentials"]["username"], self._config["credentials"]["password"])
            self._logger.info("Logged in as {}".format(self._config["credentials"]["username"]))
        else:
            self._logger.error("No creds provided")
            raise ConfigError("Must provide OAuth2 or username/password")
        return r

    def authorize_oauth(self):
        scopes = ["identity", "history", "save", "submit", "vote", "read", "edit", "privatemessages"]
        print(self._r.get_authorize_url("uniqueKey", " ".join(scopes), True))

    def post_comment(self, body):
        self._thread.add_comment("{}: {}".format(int(time.time()), body))

    def shitpost(self, delay_override=None):
        delay = delay_override or self._config["bot"].get("delay", 2)
        limit = self._config["bot"].get("limit", 0)
        self._logger.info("Starting shitposting with {} seconds between comments.".format(delay))
        if limit:
            self._logger.info("Stopping after {} comments.".format(limit))
        posted = 0
        start = time.time()
        shitposter = Faker()
        try:
            while True:
                if posted % 10 == 0:
                    self._logger.debug("{} comments posted so far.".format(posted))
                if limit and posted >= limit:
                    self._logger.info("Quitting due to limit reached.")
                    break
                self.post_comment(shitposter.text())
                posted += 1
                time.sleep(delay)
        except KeyboardInterrupt:
            self._logger.info("Stopping due to user abort.")
            self._logger.info("{} comments were posted in {} seconds.".format(posted, int(time.time() - start)))
