#coding=utf-8

import datetime
import re

import tablib

from libs.utils import strfdate
from libs import utils

try:
    from openpyxl.utils.exceptions import InvalidFileException
except:
    from tablib.packages.openpyxl.shared.exc import InvalidFileException

from apps.exceptions import CustomError

DATETIME_FORMAT = '%Y-%m-%d %H:%M'
DATETIME_FORMAT1 = '%Y-%m-%d %H:%M:%S'
DATE_FORMAT = '%Y-%m-%d'

class Formater():
    @staticmethod
    def formatStr(value):
        res = u''
        if value != None:
            try:
                res = str(value)
            except:
                pass
        return res

    @staticmethod
    def formatStrTime(value):
        res = u''
        if value != None:
            if isinstance(value, datetime.datetime):
                res = value.strftime('%Y-%m-%d %H:%M')
            elif isinstance(value, str):
                res = value
        return res

    @staticmethod
    def formatStrTimeS(value):
        res = u''
        if value != None:
            if isinstance(value, datetime.datetime):
                res = value.strftime('%Y-%m-%d %H:%M:%S')
            elif isinstance(value, str):
                res = value
        return res

    @staticmethod
    def formatStrDate(value):
        res = u''
        if value != None:
            if isinstance(value, datetime.date):
                res = strfdate(value)
            elif isinstance(value, str):
                res = value
        return res

class ExcelImporter():
    def getExcelData(self,file):
        if not file:
            raise CustomError(u'请上传数据文件')
        try:
            data = tablib.import_set(file.read(), format='xlsx').dict
            if not len(data):
                raise CustomError(u'上传的文件内没有发现数据')
            return data
        except InvalidFileException:
            raise CustomError(u'请上传<strong>xlsx</strong>格式的数据文件，老版本的xls格式不被支持！')

    def validRow(self,row):
        data = {}
        for (k,v) in self.fields.items():
            is_required = v[0]
            format_proc = v[1]

            try:
                value = row[k]
            except:
                raise CustomError(u'缺少[%s]列，请检查模板文件或重新下载' % k)

            if is_required and value == None:
                raise CustomError(u'%s：为必填项' % k)

            if format_proc and value != None:
                try:
                    value = format_proc(value)
                except CustomError as e:
                    raise CustomError(u'%s：错误的值[%s]' % (k,e.get_error_msg()))

            data[k] = value
        return data

    @staticmethod
    def formatUnicode(value):
        try:
            return str(value).strip(u' ')
        except:
            return ''

    @staticmethod
    def formatDateTime(value):
        try:
            res = datetime.datetime.strptime(value, '%Y-%m-%d %H:%M:%S')
        except:
            try:
                res = datetime.datetime.strptime(value, '%Y-%m-%d')
            except:
                raise CustomError(u'格式为：2018-01-01 或 2018-01-01 00:00:00')
        return res

    @staticmethod
    def formatInt(value):
        try:
            return int(float(str(value).strip(u' ')))
        except:
            raise CustomError(u'不能转换为整数')

    @staticmethod
    def formatFloat(value):
        try:
            return round(float(str(value).strip(u' ')) or 0,2)
        except:
            raise CustomError(u'不能转换为小数')

    @staticmethod
    def formatFloatGtZ(value):
        v = ExcelImporter.formatFloat(value)
        if v <= 0:
            raise CustomError(u'必须大于0')
        return v

    @staticmethod
    def formatFloatGeZ(value):
        v = ExcelImporter.formatFloat(value)
        if v < 0:
            raise CustomError(u'必须大于等于0')
        return v

    @staticmethod
    def formatTel(value):
        try:
            value = str(value).strip(u' ')
        except:
            value = ''
        if value == '':
            return value
        is_mobile = re.match(r'^0?(13[0-9]|14[0-9]|15[0-9]|17[0-9]|18[0-9]|19[0-9]|166)[0-9]{8}$', value)
        is_tel = re.match(r'^([0-9]{3,4}-)?[0-9]{7,8}$', value)
        if not (is_mobile or is_tel):
            raise CustomError(u'不合法的手机号或者固话号')
        return value

class Filter():
    @staticmethod
    def limit(rows, start, end):
        if start and end:
            rows = rows[start:end]
        else:
            if start:
                rows = rows[start:]
            elif end:
                rows = rows[:end]
        return rows

class Shower():
    def __init__(self, fields_map, show_data):
        if isinstance(show_data, dict):
            self.show_type = 'dict'
            self.fields,self.kips = Shower.getFkips(fields_map, show_data)
        elif isinstance(show_data, (list, tuple)):
            self.show_type = 'arr'
            self.fields, self.ips = Shower.getFips(fields_map, show_data)

    def getNeedFields(self):
        return self.fields

    def format(self, rows,start,end):
        rows = Filter.limit(rows,start,end)
        if self.show_type == 'dict':
            return self.formatDict(rows)
        elif self.show_type == 'arr':
            return self.formatArr(rows)
        return []

    def formatArr(self,rows):
        data = []
        for row in rows:
            item = []
            for ip in self.ips:
                if ip[1]:
                    value = ip[1](row[ip[0]])
                else:
                    value = row[ip[0]]
                item.append(value)
            data.append(item)
        return data

    def formatDict(self,rows):
        data = []
        for row in rows:
            item = {}
            for kip in self.kips:
                if kip[2]:
                    value = kip[2](row[kip[1]])
                else:
                    value = row[kip[1]]
                item[kip[0]] = value
            data.append(item)
        return data

    @staticmethod
    def getFips(fields_map, show_arr):
        fields = []
        ips = []
        index = 0

        for item in show_arr:
            field = Shower.getFieldByKey(fields_map,item)
            if field:
                fields.append(field[0])
                ip = (index, field[1])
                ips.append(ip)
                index += 1
        return fields, ips

    @staticmethod
    def getFkips(fields_map, show_map):
        fields = []
        kips = []
        index = 0

        for (k,v) in show_map.items():
            field = Shower.getFieldByKey(fields_map,v)
            if field:
                fields.append(field[0])
                kip = (k, index, field[1])
                kips.append(kip)
                index += 1
        return fields, kips

    @staticmethod
    def getFieldByKey(fields_map,key):
        try:
            return fields_map[key]
        except:
            return None

class CustomShower(Shower):
    def __init__(self, fields_map, show_data, user):
        Shower.__init__(self,fields_map,show_data)
        self.user = user

    def format(self, rows,start,end):
        rows = Filter.limit(rows,start,end)
        if self.show_type == 'dict':
            return self.formatDict(rows)
        elif self.show_type == 'arr':
            return self.formatArr(rows)
        return []

    def getNeedFields(self):
        return self.fields

    def formatArr(self,rows):
        data = []
        for row in rows:
            item = []
            for ip in self.ips:
                if ip[1]:
                    value = ip[1](row[ip[0]],self.user)
                else:
                    value = row[ip[0]]
                item.append(value)
            data.append(item)
        return data

    def formatDict(self,rows):
        data = []
        for row in rows:
            item = {}
            for kip in self.kips:
                if kip[2]:
                    value = kip[2](row[kip[1]],self.user)
                else:
                    value = row[kip[1]]
                item[kip[0]] = value
            data.append(item)
        return data

    def formatAmountShow(self,value):
        #from apps.foundation.models import Config
        #num = Config.objects.get_proprty(self.user.company.id, Config.KEY_PART_ENTRY_PRICE_ROUND)
        #if not num:
        #    num = 4
        #return round(float(value or 0) / 1000000, int(num))
        return Formater.formatAmountShow(value)


def clean_datetime_range(data, fieldname, source=None):
    if data is not None and fieldname in data and data[fieldname] != '':
        if data is not None and source in data and data[source] == 'touch':
            t = data[fieldname].split('T')[0]
            data = data.copy()
            data[fieldname + '_0'] = t
            data[fieldname + '_1'] = t + ' 23:59:59'
        else:
            t = data[fieldname].split(' - ')
            data = data.copy()
            data[fieldname+'_0'] = t[0]
            data[fieldname+'_1'] = t[1] + ' 23:59:59'
        data.pop(fieldname)
    return data

def clean_date_range(data, fieldname):
    if data is not None and fieldname in data and data[fieldname] != '':
        t = data[fieldname].split(' - ')
        data = data.copy()
        data[fieldname+'_0'] = t[0]
        data[fieldname+'_1'] = t[1]
        data.pop(fieldname)
    return data