#!/usr/bin/env python3
# coding: utf-8
"""
    Создает простую html страничку с списком котировок и статусами
    1) пробегаемся по котировкам
    2) выделяем котировка с ошибками
    3) отдельно выписываем сообщения об ошибках при тестах (сделать сохранение этих ошибок куданибудь)
"""
import sys
import threading
import time
from datetime import datetime, timedelta
import pystache
from stocks3.share.curl import get_http_code_retry
from stocks3.core.source import SourceLoader
import stocks3
from stocks3.core.exception import S3Exception
from stocks3.export.exporter import make_exporter
import argparse

SOURCES_QUANTITY = 31

template = """
<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>stocks status</title>
    <link rel="icon" href="/static/images/favicon.png" type="image/png">
    <link rel="stylesheet" href="https://yandex.st/bootstrap/3.1.1/css/bootstrap.min.css">
</head>
<body>
<div class="container">
    <table class="table table-striped table-hover table-condensed">
        {{# entries }}
        {{# type }}
        <tr><td>{{ count }}</td><td colspan={{ cols }}> {{ message }}</td></tr>
        {{/ type }}
        {{^ type }}
        <tr><td>{{ count }}</td>{{# message }}<td>{{ . }}</td>{{/ message }}</tr>
        {{/ type }}
        {{/ entries }}
    </table>
    <hr>
    <footer>generation time: {{ now }}</footer>
</div>
<script src="https://yandex.st/jquery/2.0.3/jquery.min.js"></script>
<script src="https://yandex.st/bootstrap/3.1.1/js/bootstrap.min.js"></script>
</body>
</html>
"""


def write_html(messages):
    if len(messages) == 0:
        messages.append('All is ok!')
    cols = max([len(message) if not isinstance(message, str) else 1 for message in messages])
    entries = []
    count = 1
    for message in messages:
        entries.append({
            'count': count,
            'type': isinstance(message, str),
            'message': message,
        })
        count += 1

    data = {
        'now': datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
        'cols': cols,
        'entries': entries,
    }
    return pystache.render(template, data)


disabled_checkers_checks = [40003]


class Worker(threading.Thread):
    def __init__(self, source_name, source):
        threading.Thread.__init__(self)
        self._sourceName = source_name
        self._source = source
        self._stoper = threading.Event()
        self.failed_prices = []
        self.message = ''
        self.res = False

    def stop(self):
        self._stoper.set()

    def stopped(self):
        return self._stoper.isSet()

    def get_source(self):
        return self._sourceName

    def run(self):
        self.res = True
        try:
            try:
                self.failed_prices = self._source.transfer(test=True)
                new_failed_prices = []
                for price in self.failed_prices:
                    if price.quote.quote_id not in disabled_checkers_checks:
                        new_failed_prices.append(price)
                self.failed_prices = new_failed_prices
            except S3Exception as msg:
                self.res = False
                self.message = 'Src: ' + self._sourceName + ' Msg:' + str(msg)
            except KeyboardInterrupt:
                sys.exit(-1)
            except Exception as msg:
                self.res = False
                self.message = 'Src: ' + self._sourceName + ' Msg:' + str(msg)
            finally:
                self._source.clean()
        except Exception as e:
            self.message = "CLEANERROR: %s: %s\n" % (self._sourceName, e)
        finally:
            self.stop()


class ImportsTest(object):
    def __init__(self):
        self.messages = []
        self.opts = None
        self.sources = None
        self.exporter_opts = None
        self.exporter = None

    def set_up(self):
        stocks3.load_modules()
        loader = SourceLoader()
        self.sources = list(loader.get_active_sources())
        self.exporter = make_exporter(self.sources)

    def test_urls(self):
        # Тестируем урлы
        sources_list = list(self.sources)
        for sourceName, source in sources_list:
            for transport in source.transports:
                url = transport.url if 'url' in transport.__dict__ else None
                if url is not None:
                    http_code, message = get_http_code_retry(url)
                    if http_code not in [200, 401]:
                        self.messages.append(
                            'Url <b>{0}</b> is not responding right. Return code is {1}'.format(url, http_code))
        if len(sources_list) != SOURCES_QUANTITY:
            self.messages.append('Not matched sources count! (%d|%d)' % (len(sources_list), SOURCES_QUANTITY))

    def test_data(self):
        # Тестируем source
        res = True
        message = 'Some strange happens while import'
        workers = []
        try:
            for sourceName, source in self.sources:
                w = Worker(sourceName, source)
                workers.append(w)
                w.start()
            for worker in workers:
                while not worker.stopped(): time.sleep(1)
                if not worker.res:
                    res = False
                    message = worker.message
                if len(worker.failed_prices) != 0:
                    for pr in worker.failed_prices:
                        self.messages.append('Failed check:' + pr.quote.quote_id)
        except Exception as msg:
            res = False
            message = str(msg)
        if res:
            self.messages.append(message)

    def test_oldest_quotes(self):
        if datetime.now().month == 1 and 1 <= datetime.now().day <= 10:
            return

        fails = []
        quote_set = {}
        for quote in self.exporter.list_of_quotes_for_export():
            if not quote.has_flag('item') or quote.has_flag('ignore_dates'):
                continue
            quote_set[quote.quote_id] = quote
        data = self.exporter.reader.db.stocks.aggregate([
            {"$match": {"deleted": {"$ne": True}}},
            {"$sort": {"date": 1}},
            {"$group": {"_id": {"id": "$id",
                                "region": "$region"},
                        "lastDate": {"$last": "$date"}}}
        ])
        if isinstance(data, dict):  # fallback для старых монг
            data = data["result"]
        for record in data:
            quote_id = record["_id"]["id"]
            quote_region = record["_id"]["region"]
            quote_date = record["lastDate"]
            if quote_id not in list(quote_set.keys()):  # or max_date is None:
                continue
            if datetime.now().date() - datetime.strptime(quote_date, '%Y-%m-%d').date() > timedelta(days=3):
                fails.append(
                    (quote_set[quote_id].name, quote_id, quote_region, quote_date, quote_set[quote_id].source.sourceId))

        fails = sorted(fails, key=lambda f: f[1])
        if len(fails):
            for fail in fails:
                self.messages.append(('Old stock', fail[0], fail[1], fail[2], fail[3], fail[4]))


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("-l", "--log", help="Just log messages", action='store_true', required=False)
    args = parser.parse_args()

    tester = ImportsTest()
    tester.set_up()
    tester.test_data()
    tester.test_urls()
    tester.test_oldest_quotes()

    if args.log:
        for message in tester.messages:
            if isinstance(message, str):
                print(message)
            else:
                print("\t".join([str(m) for m in message]))
    else:
        print(write_html(tester.messages))
    pass


if __name__ == "__main__":
    main()
