import requests
import lxml.html
import datetime
import re
import urlparse
from mrq import context
from mrq.context import connections, log
from mrq.job import queue_job
from mrq.task import Task
from mrq.queue import Queue


class Fetch(Task):

    def run(self, params):

        context.setup_context()

        collection = connections.mongodb_jobs.simple_crawler_urls

        response = requests.get(params["url"])

        if response.status_code != 200:
            log.warning("Got status %s on page %s (Queued from %s)" % (
                response.status_code, response.url, params.get("from")
            ))
            return False

        # Store redirects
        if response.url != params["url"]:
            collection.update({"_id": params["url"]}, {"$set": {
                "redirected_to": response.url,
                "fetched_date": datetime.datetime.now()
            }})

        document = lxml.html.fromstring(response.content)

        document.make_links_absolute(response.url)

        queued_count = 0

        document_domain = urlparse.urlparse(response.url).netloc

        for (element, attribute, link, pos) in document.iterlinks():

            link = re.sub("#.*", "", link or "")

            if not link:
                continue

            domain = urlparse.urlparse(link).netloc

            # Don't follow external links for this example
            if domain != document_domain:
                continue

            # We don't want to re-queue URLs twice. If we try to insert a duplicate,
            # pymongo will throw an error
            try:
                collection.insert({"_id": link})
            except:
                continue

            queue_job("crawler.Fetch", {
                "url": link,
                "from": params["url"]
            }, queue="crawl")
            queued_count += 1

        stored_data = {
            "_id": response.url,
            "queued_urls": queued_count,
            "html_length": len(response.content),
            "fetched_date": datetime.datetime.now()
        }

        collection.update(
            {"_id": response.url},
            stored_data,
            upsert=True
        )

        return True


class Report(Task):

    def run(self, params):

        collection = connections.mongodb_jobs.simple_crawler_urls

        print()
        print( "Crawl stats")
        print( "===========")
        print( "URLs queued: %s" % collection.find().count())
        print( "URLs successfully crawled: %s" % collection.find({"fetched_date": {"$exists": True}}).count())
        print( "URLs redirected: %s" % collection.find({"redirected_to": {"$exists": True}}).count())
        print( "Bytes fetched: %s" % (list(collection.aggregate(
            {"$group": {"_id": None, "sum": {"$sum": "$html_length"}}}
        )) or [{}])[0].get("sum", 0))
        print()


class Reset(Task):

    def run(self, params):

        collection = connections.mongodb_jobs.simple_crawler_urls

        collection.remove({})

        Queue("crawl").empty()
