import md5
import json
from datetime import datetime
from datacloud.dev_utils.logging.logger import get_basic_logger

logger = get_basic_logger(__name__)


__all__ = [
    'ScoreApiLogParser'
]


TAG = 'LogParser'
MAX_DATA_LEN = 20000


class LogParser(object):
    def __init__(self, required_fields=None, other_fields=None):
        self._required_fields = required_fields or []
        self._other_fields = other_fields or []
        assert self._required_fields or self._other_fields, '[{}]: `required` or `other` fierd must be specified'.format(TAG)

    def parse(self, data_str):
        data_str = data_str[:MAX_DATA_LEN]
        try:
            data = json.loads(data_str)
        except (ValueError, TypeError) as ex:
            logger.warn('[{}] Failed to parse json: {}'.format(TAG, ex))
            logger.warn('Data is :{}'.format(data_str))
            return self.create_trash_rec(data_str), False
        rec = {}
        for field in self._required_fields:
            if field in data:
                rec[field] = data[field]
            else:
                logger.warn(
                    '[{}] Field `{}` not found in raw data :/'.format(TAG, field))
                return self.create_trash_rec(data_str), False
        for field in self._other_fields:
            rec[field] = data.get(field, None)
        return rec, True

    def parse_raw_line(self, line):
        return list(map(self.parse, filter(None, line.split('\n'))))

    def create_trash_rec(self, data_str):
        return {
            'timestamp': datetime.now().replace(microsecond=0).isoformat(),
            'hash': md5.new(data_str).hexdigest(),
            'data': data_str,
            'other': None
        }


class ScoreApiLogParser(LogParser):
    def __init__(self):
        super(ScoreApiLogParser, self).__init__(
            required_fields=['timestamp', 'req_id', 'status'],
            other_fields=['request', 'req_body', 'resp_body', 'user_agent', 'remote_addr', 'other', 'resp_time', 'dc', 'host', 'blnsr_req_id']
        )

    def parse(self, data_str):
        data_str = data_str[:MAX_DATA_LEN]
        rec, is_parsed = super(ScoreApiLogParser, self).parse(data_str)
        if not is_parsed:
            return rec, is_parsed
        try:
            rec['req_body'] = json.loads(rec['req_body'])
            rec['resp_body'] = json.loads(rec['resp_body'])
            rec['method'] = self._get_method(rec['request'])

            url_parts = self._get_url_parts(rec['request'])
            rec['partner_id'] = url_parts[2] if len(url_parts) >= 3 else None
            rec['req_type'] = url_parts[3] if len(url_parts) >= 4 else None
        except (ValueError, TypeError) as ex:
            logger.warn('[{}] Can not parse `req_body` or `resp_body`'.format(TAG))
            return self.create_trash_rec(data_str), False
        return rec, True

    def _get_method(self, request):
        if not request:
            return None
        parts = request.split(' ')
        if not parts:
            return None
        return parts[0]

    def _get_url_parts(self, request):
        if not request:
            return []
        parts = request.split(' ')
        if len(parts) < 2:
            return []
        url = parts[1]
        if not url:
            return []
        return list(filter(None, url.split('/')))
