#!/usr/bin/env python3

"""domain.py: /domain API endpoint"""
__author__      = "Radek Hranicky"
__author__      = "Doktor Databaze"

import logging
import json
import copy

from math import ceil

from sqlalchemy.sql.expression import true, false

from flask import request, current_app
from flask_restx import Resource, fields

from api.apiConfig import api
from api.reqparse import pagination, filter_sort
from api.queryparse import sort_params, filter_params



from database import db
#from database.models import OffenseSource
from database.models import *

ignorelist = ["raw.githubusercontent.com"]

geo_model = api.model('geo_model',
{
    "ip": fields.String(),
    "country": fields.String(),
    "region": fields.String(),
    "city": fields.String(),
    "loc": fields.String(),
    "org": fields.String()
})

cls_result_model = api.model('cls_result_model',
{
    "classifier_name": fields.String(),
    "final": fields.Boolean(),
    "error_description": fields.String(),
    "badness": fields.Float(),
    "accuracy": fields.Float(),
    "explanation": fields.List(fields.String),
    "final": fields.Boolean(),
    "created": fields.String()
})

domain_model = api.model('domain_model',
{
    "id": fields.Integer(),
    "domain_name": fields.String(),
    "offense_count": fields.Integer(),
    "event_flow_count": fields.Integer(),
    "geo_data": fields.List(fields.Nested(geo_model)),
    "results": fields.List(fields.Nested(cls_result_model))
})

domains_model = api.model('domains_model',
{
    "domains": fields.List(fields.Nested(domain_model)),
    "total": fields.Integer(),
    "page": fields.Integer(),
    "per_page": fields.Integer(),
    "pages": fields.Integer()
})



log = logging.getLogger(__name__)
ns = api.namespace('domain', description='Displays domain info')


logger = logging.getLogger('domainradar')

def pager(list, page, per_page):
    return list[(page-1)*per_page:page*per_page]

@ns.route('')
class Domain(Resource):

    @api.marshal_with(domains_model)
    @api.expect(pagination, filter_sort)
    def get(self):
        """
        Returns info about domain threat analysis
        """
        args = pagination.parse_args()
        page = args.get('page', 0)
        per_page = args.get('per_page', 0)

        args = filter_sort.parse_args()
        q = args.get('q')
        sort = args.get('sort', '-id')
        filters = args.get('filter', '')
        grouping = args.get('group', '')

        domains = []

        result_page = DomainName.query \
            .filter(DomainName.analyzed == true()) \
            .order_by(DomainName.id.desc())
            #.paginate(page, per_page) 

        if (q):
            result_page = result_page.filter(DomainName.domain_name.contains(q))

        
        analyzed_domains = result_page.all()

        for domain_name in analyzed_domains:

            if domain_name.domain_name in ignorelist:
                continue

            geo_record = ExternalData.query.filter(ExternalData.domain_name == domain_name.domain_name).filter(ExternalData.data_type == 'geo').first()

            if geo_record == None:
                geo_data = []
            else:
                geo_data = json.loads(geo_record.contents)['data']

            classifier_results = []
            json_result = json.loads(domain_name.result)
            for classifier in json_result:
                classifier_results.append(json_result[classifier])


            # Find offense + eventflow count
            ips = []
            domain_ip_mappings = DomainIPMapping.query.filter(DomainIPMapping.domain_name == domain_name.domain_name).all()
            if domain_ip_mappings:
                for domain_ip_mapping in domain_ip_mappings:
                        ips.append(domain_ip_mapping.ip_address)

            offense_count = 0
            event_flow_count = 0

            if ips:
                for ip in ips:
                    offense_sources = OffenseSource.query.filter(OffenseSource.source_ip == ip).all()
                    if offense_sources:
                        for offense_source in offense_sources:
                            offense_count += offense_source.offense_count
                            event_flow_count += offense_source.event_flow_count

            domain = {
                "id": domain_name.id,
                "domain_name": domain_name.domain_name,
                "offense_count": offense_count,
                "event_flow_count": event_flow_count,
                "geo_data": copy.deepcopy(geo_data),
                "results": classifier_results
            }

            domains.append(domain)
        
        # tada, list of domains as it was meant to be

        # now we can filter
        if (filters):
            filter_strings = filters.split(',')
            for filter_string in filter_strings:
                key, op, value = filter_params(filter_string)
                domains = list(filter(lambda x: op(key(x), value), domains))

        # and sort
        if (sort != '-id'):
            key, reverse = sort_params(sort)
            domains.sort(key=key, reverse=reverse)

        return {
            "domains": pager(domains, page, per_page), 
            "total": len(domains), #result_page.total,
            "page": page, #result_page.page,
            "per_page": per_page, #result_page.per_page,
            "pages": ceil(len(domains) / per_page) #result_page.pages
        }
